diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
 
 | Haskell bindings version | Bundled Binaryen version |
 | ------------------------ | ------------------------ |
-| 0.0.5.\*                 | version_98               |
+| 0.0.6.\*                 | version_99               |
 
 Older versions of this package links against the system-wide `binaryen` library,
 so before building the package, please check the Binaryen version and make sure
@@ -28,6 +28,7 @@
 | 0.0.2.\*                 | version_94               |
 | 0.0.3.\*                 | version_96               |
 | 0.0.4.\*                 | version_97               |
+| 0.0.5.\*                 | version_98               |
 
 ## How to build
 
diff --git a/binaryen.cabal b/binaryen.cabal
--- a/binaryen.cabal
+++ b/binaryen.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: dd229f4cad11bdebeaef89df68685de75858bc5d1ec3d969f606f0519e5e34b8
+-- hash: 15122c50a2315bce9fd4a209364778dc7a50ec2775a053a7501cd0a59659de50
 
 name:           binaryen
-version:        0.0.5.0
+version:        0.0.6.0
 synopsis:       Haskell bindings to binaryen
 description:    Haskell bindings to [binaryen](https://github.com/WebAssembly/binaryen). Provides complete bindings to the C API, which can be useful for building WebAssembly toolchains in Haskell.
 category:       Compiler
@@ -28,10 +28,11 @@
     binaryen/LICENSE
     binaryen/media/example.png
     binaryen/README.md
+    binaryen/requirements-dev.txt
     binaryen/scripts/__init__.py
+    binaryen/scripts/binaryen-lit.in
     binaryen/scripts/clang-format-diff.sh
     binaryen/scripts/clang-tidy-diff.sh
-    binaryen/scripts/clean_c_api_trace.py
     binaryen/scripts/embedwat.py
     binaryen/scripts/emcc-tests.sh
     binaryen/scripts/fuzz_opt.py
@@ -40,7 +41,7 @@
     binaryen/scripts/fuzz_relooper.py
     binaryen/scripts/fuzz_shell.js
     binaryen/scripts/gen-s-parser.py
-    binaryen/scripts/process_optimize_instructions.py
+    binaryen/scripts/not.py
     binaryen/scripts/storage.py
     binaryen/scripts/strip_local_names.py
     binaryen/scripts/test/__init__.py
@@ -57,10 +58,7 @@
     binaryen/scripts/test/wasm_opt.py
     binaryen/scripts/validation_shell.js
     binaryen/scripts/wasm2js.js
-    binaryen/src/abi/abi.h
     binaryen/src/abi/js.h
-    binaryen/src/abi/stack.h
-    binaryen/src/abi/wasm-object.h
     binaryen/src/asm_v_wasm.h
     binaryen/src/asmjs/asm_v_wasm.cpp
     binaryen/src/asmjs/asmangle.cpp
@@ -120,6 +118,8 @@
     binaryen/src/ir/manipulation.h
     binaryen/src/ir/match.h
     binaryen/src/ir/memory-utils.h
+    binaryen/src/ir/module-splitting.cpp
+    binaryen/src/ir/module-splitting.h
     binaryen/src/ir/module-utils.h
     binaryen/src/ir/names.h
     binaryen/src/ir/parents.h
@@ -155,7 +155,6 @@
     binaryen/src/passes/DuplicateFunctionElimination.cpp
     binaryen/src/passes/DuplicateImportElimination.cpp
     binaryen/src/passes/DWARF.cpp
-    binaryen/src/passes/EmscriptenPIC.cpp
     binaryen/src/passes/ExtractFunction.cpp
     binaryen/src/passes/Flatten.cpp
     binaryen/src/passes/FuncCastEmulation.cpp
@@ -170,6 +169,7 @@
     binaryen/src/passes/LocalCSE.cpp
     binaryen/src/passes/LogExecution.cpp
     binaryen/src/passes/LoopInvariantCodeMotion.cpp
+    binaryen/src/passes/Memory64Lowering.cpp
     binaryen/src/passes/MemoryPacking.cpp
     binaryen/src/passes/MergeBlocks.cpp
     binaryen/src/passes/MergeLocals.cpp
@@ -199,14 +199,12 @@
     binaryen/src/passes/RemoveUnusedNames.cpp
     binaryen/src/passes/ReorderFunctions.cpp
     binaryen/src/passes/ReorderLocals.cpp
-    binaryen/src/passes/ReplaceStackPointer.cpp
     binaryen/src/passes/ReReloop.cpp
     binaryen/src/passes/RoundTrip.cpp
     binaryen/src/passes/SafeHeap.cpp
     binaryen/src/passes/SimplifyGlobals.cpp
     binaryen/src/passes/SimplifyLocals.cpp
     binaryen/src/passes/Souperify.cpp
-    binaryen/src/passes/SpillPointers.cpp
     binaryen/src/passes/SSAify.cpp
     binaryen/src/passes/StackCheck.cpp
     binaryen/src/passes/StackIR.cpp
@@ -246,6 +244,7 @@
     binaryen/src/support/safe_integer.h
     binaryen/src/support/small_vector.h
     binaryen/src/support/sorted_vector.h
+    binaryen/src/support/space.h
     binaryen/src/support/string.h
     binaryen/src/support/threads.cpp
     binaryen/src/support/threads.h
@@ -270,17 +269,19 @@
     binaryen/src/tools/wasm-opt.cpp
     binaryen/src/tools/wasm-reduce.cpp
     binaryen/src/tools/wasm-shell.cpp
+    binaryen/src/tools/wasm-split.cpp
     binaryen/src/tools/wasm2c-wrapper.h
     binaryen/src/tools/wasm2js.cpp
     binaryen/src/wasm-binary.h
     binaryen/src/wasm-builder.h
     binaryen/src/wasm-debug.h
+    binaryen/src/wasm-delegations-fields.h
+    binaryen/src/wasm-delegations.h
     binaryen/src/wasm-emscripten.h
     binaryen/src/wasm-features.h
     binaryen/src/wasm-interpreter.h
     binaryen/src/wasm-io.h
     binaryen/src/wasm-module-building.h
-    binaryen/src/wasm-printing.h
     binaryen/src/wasm-s-parser.h
     binaryen/src/wasm-stack.h
     binaryen/src/wasm-traversal.h
@@ -313,7 +314,6 @@
     binaryen/test/atomics64.wast.from-wast
     binaryen/test/atomics64.wast.fromBinary
     binaryen/test/atomics64.wast.fromBinary.noDebugInfo
-    binaryen/test/bad_params.asm.js
     binaryen/test/bigswitch.cpp
     binaryen/test/bigswitch.txt
     binaryen/test/binaryen.js/atomics.js
@@ -446,7 +446,6 @@
     binaryen/test/ctor-eval/unsafe_store3.wast
     binaryen/test/ctor-eval/unsafe_store3.wast.ctors
     binaryen/test/ctor-eval/unsafe_store3.wast.out
-    binaryen/test/debugInfo.asm.js
     binaryen/test/duplicate_types.wast
     binaryen/test/duplicate_types.wast.from-wast
     binaryen/test/duplicate_types.wast.fromBinary
@@ -457,13 +456,8 @@
     binaryen/test/duplicated_names_collision.wasm.fromBinary
     binaryen/test/dylib.wasm
     binaryen/test/dylib.wasm.fromBinary
-    binaryen/test/dynamicLibrary.asm.js
     binaryen/test/elided-br.wasm
     binaryen/test/elided-br.wasm.fromBinary
-    binaryen/test/emcc_hello_world.asm.js
-    binaryen/test/emcc_O2_hello_world.asm.js
-    binaryen/test/empty.asm.js
-    binaryen/test/empty_4GB.asm.js
     binaryen/test/empty_imported_table.wast
     binaryen/test/empty_imported_table.wast.from-wast
     binaryen/test/empty_imported_table.wast.fromBinary
@@ -480,7 +474,6 @@
     binaryen/test/example/c-api-hello-world.txt
     binaryen/test/example/c-api-kitchen-sink.c
     binaryen/test/example/c-api-kitchen-sink.txt
-    binaryen/test/example/c-api-kitchen-sink.txt.txt
     binaryen/test/example/c-api-relooper-unreachable-if.cpp
     binaryen/test/example/c-api-relooper-unreachable-if.txt
     binaryen/test/example/c-api-unused-mem.cpp
@@ -489,8 +482,12 @@
     binaryen/test/example/cpp-threads.txt
     binaryen/test/example/cpp-unit.cpp
     binaryen/test/example/cpp-unit.txt
+    binaryen/test/example/hash.cpp
+    binaryen/test/example/hash.txt
     binaryen/test/example/match.cpp
     binaryen/test/example/match.txt
+    binaryen/test/example/module-splitting.cpp
+    binaryen/test/example/module-splitting.txt
     binaryen/test/example/relooper-fuzz.c
     binaryen/test/example/relooper-fuzz.txt
     binaryen/test/example/relooper-fuzz1.c
@@ -513,8 +510,12 @@
     binaryen/test/example/relooper-merge7.txt
     binaryen/test/example/small_vector.cpp
     binaryen/test/example/small_vector.txt
+    binaryen/test/example/space.cpp
+    binaryen/test/example/space.txt
     binaryen/test/example/stack-utils.cpp
     binaryen/test/example/stack-utils.txt
+    binaryen/test/example/type-builder.cpp
+    binaryen/test/example/type-builder.txt
     binaryen/test/example/typeinfo.cpp
     binaryen/test/example/typeinfo.txt
     binaryen/test/exception-handling.wast
@@ -525,6 +526,10 @@
     binaryen/test/export-import.wast.from-wast
     binaryen/test/export-import.wast.fromBinary
     binaryen/test/export-import.wast.fromBinary.noDebugInfo
+    binaryen/test/extended-names.wast
+    binaryen/test/extended-names.wast.from-wast
+    binaryen/test/extended-names.wast.fromBinary
+    binaryen/test/extended-names.wast.fromBinary.noDebugInfo
     binaryen/test/externref.wast.from-wast
     binaryen/test/externref.wast.fromBinary
     binaryen/test/externref.wast.fromBinary.noDebugInfo
@@ -563,16 +568,18 @@
     binaryen/test/grow_memory.wast.from-wast
     binaryen/test/grow_memory.wast.fromBinary
     binaryen/test/grow_memory.wast.fromBinary.noDebugInfo
+    binaryen/test/heap-types.wast
+    binaryen/test/heap-types.wast.from-wast
+    binaryen/test/heap-types.wast.fromBinary
+    binaryen/test/heap-types.wast.fromBinary.noDebugInfo
     binaryen/test/hello_libcxx.cpp
     binaryen/test/hello_libcxx.txt
-    binaryen/test/hello_world.asm.js
     binaryen/test/hello_world.c
     binaryen/test/hello_world.txt
     binaryen/test/hello_world.wast.from-wast
     binaryen/test/hello_world.wast.fromBinary
     binaryen/test/hello_world.wast.fromBinary.noDebugInfo
     binaryen/test/hello_world.wat
-    binaryen/test/i64-setTempRet0.asm.js
     binaryen/test/imported_memory.wast
     binaryen/test/imported_memory.wast.from-wast
     binaryen/test/imported_memory.wast.fromBinary
@@ -581,7 +588,6 @@
     binaryen/test/imported_memory_growth.wast.from-wast
     binaryen/test/imported_memory_growth.wast.fromBinary
     binaryen/test/imported_memory_growth.wast.fromBinary.noDebugInfo
-    binaryen/test/importedSignCast.asm.js
     binaryen/test/int_ops.c
     binaryen/test/int_ops.emcc
     binaryen/test/int_ops.post.js
@@ -597,11 +603,27 @@
     binaryen/test/linker/foo.c
     binaryen/test/linker/main.c
     binaryen/test/linker/quux.c
+    binaryen/test/lit/CMakeLists.txt
+    binaryen/test/lit/lit.cfg.py
+    binaryen/test/lit/lit.site.cfg.py.in
+    binaryen/test/lit/parse-error.wast
+    binaryen/test/lit/validation/shared-memory.wast
+    binaryen/test/lit/wasm-emscripten-finalize/bigint.wat
+    binaryen/test/lit/wasm-emscripten-finalize/passive-pic.wat
+    binaryen/test/lit/wasm-split/basic.wast
+    binaryen/test/lit/wasm-split/call_exports.mjs
+    binaryen/test/lit/wasm-split/export-name-already-exists.wast
+    binaryen/test/lit/wasm-split/initial-table.wast
+    binaryen/test/lit/wasm-split/instrument-funcs.wast
+    binaryen/test/lit/wasm-split/instrument-memory-too-small.wast
+    binaryen/test/lit/wasm-split/invalid-options.wast
+    binaryen/test/lit/wasm-split/mismatched-hashes.wast
+    binaryen/test/lit/wasm-split/name-collision.wast
+    binaryen/test/lit/wasm-split/profile-guided.wast
+    binaryen/test/lit/wasm-split/verbose.wast
     binaryen/test/lld/basic_safe_stack.s
     binaryen/test/lld/basic_safe_stack.wat
     binaryen/test/lld/basic_safe_stack.wat.out
-    binaryen/test/lld/bigint.wat
-    binaryen/test/lld/bigint.wat.out
     binaryen/test/lld/duplicate_imports.wat
     binaryen/test/lld/duplicate_imports.wat.out
     binaryen/test/lld/em_asm.cpp
@@ -609,6 +631,9 @@
     binaryen/test/lld/em_asm.wat.mem.mem
     binaryen/test/lld/em_asm.wat.mem.out
     binaryen/test/lld/em_asm.wat.out
+    binaryen/test/lld/em_asm64.cpp
+    binaryen/test/lld/em_asm64.wat
+    binaryen/test/lld/em_asm64.wat.out
     binaryen/test/lld/em_asm_main_thread.wat
     binaryen/test/lld/em_asm_main_thread.wat.out
     binaryen/test/lld/em_asm_O0.c
@@ -621,8 +646,6 @@
     binaryen/test/lld/em_asm_table.wat.out
     binaryen/test/lld/em_js_O0.wat
     binaryen/test/lld/em_js_O0.wat.out
-    binaryen/test/lld/gdollar_mainmodule.wat
-    binaryen/test/lld/gdollar_mainmodule.wat.out
     binaryen/test/lld/hello_world.c
     binaryen/test/lld/hello_world.passive.wat
     binaryen/test/lld/hello_world.passive.wat.out
@@ -691,8 +714,6 @@
     binaryen/test/memory-shared.wast.from-wast
     binaryen/test/memory-shared.wast.fromBinary
     binaryen/test/memory-shared.wast.fromBinary.noDebugInfo
-    binaryen/test/memorygrowth-minimal.asm.js
-    binaryen/test/memorygrowth.asm.js
     binaryen/test/metadatas.wasm
     binaryen/test/metadatas.wasm.fromBinary
     binaryen/test/metadce/all-outside.wast
@@ -739,7 +760,6 @@
     binaryen/test/metadce/threaded_unrooted_cycle.wast.dced
     binaryen/test/metadce/threaded_unrooted_cycle.wast.dced.stdout
     binaryen/test/metadce/threaded_unrooted_cycle.wast.graph.txt
-    binaryen/test/min.asm.js
     binaryen/test/min.wast
     binaryen/test/min.wast.from-wast
     binaryen/test/min.wast.fromBinary
@@ -758,8 +778,6 @@
     binaryen/test/newsyntax.wast.from-wast
     binaryen/test/newsyntax.wast.fromBinary
     binaryen/test/newsyntax.wast.fromBinary.noDebugInfo
-    binaryen/test/noffi_f32.asm.js
-    binaryen/test/noffi_i64.asm.js
     binaryen/test/nonspec-bulk-memory.wast
     binaryen/test/nonspec-bulk-memory.wast.from-wast
     binaryen/test/nonspec-bulk-memory.wast.fromBinary
@@ -825,14 +843,14 @@
     binaryen/test/passes/converge_O3_metrics.wasm
     binaryen/test/passes/dae-optimizing.txt
     binaryen/test/passes/dae-optimizing.wast
-    binaryen/test/passes/dae_enable-tail-call.txt
-    binaryen/test/passes/dae_enable-tail-call.wast
+    binaryen/test/passes/dae_all-features.txt
+    binaryen/test/passes/dae_all-features.wast
     binaryen/test/passes/dce_all-features.txt
     binaryen/test/passes/dce_all-features.wast
-    binaryen/test/passes/dce_vacuum.bin.txt
-    binaryen/test/passes/dce_vacuum.txt
-    binaryen/test/passes/dce_vacuum.wasm
-    binaryen/test/passes/dce_vacuum.wast
+    binaryen/test/passes/dce_vacuum_remove-unused-names.bin.txt
+    binaryen/test/passes/dce_vacuum_remove-unused-names.txt
+    binaryen/test/passes/dce_vacuum_remove-unused-names.wasm
+    binaryen/test/passes/dce_vacuum_remove-unused-names.wast
     binaryen/test/passes/dealign.txt
     binaryen/test/passes/dealign.wast
     binaryen/test/passes/dealign64.passes
@@ -840,8 +858,8 @@
     binaryen/test/passes/dealign64.wast
     binaryen/test/passes/denan.txt
     binaryen/test/passes/denan.wast
-    binaryen/test/passes/directize_enable-tail-call.txt
-    binaryen/test/passes/directize_enable-tail-call.wast
+    binaryen/test/passes/directize_all-features.txt
+    binaryen/test/passes/directize_all-features.wast
     binaryen/test/passes/duplicate-function-elimination_all-features.txt
     binaryen/test/passes/duplicate-function-elimination_all-features.wast
     binaryen/test/passes/duplicate-function-elimination_optimize-level=1.txt
@@ -908,6 +926,8 @@
     binaryen/test/passes/flatten_simplify-locals-nonesting_souperify_enable-threads.wast
     binaryen/test/passes/fpcast-emu.txt
     binaryen/test/passes/fpcast-emu.wast
+    binaryen/test/passes/fpcast-emu_pass-arg=max-func-params@5.txt
+    binaryen/test/passes/fpcast-emu_pass-arg=max-func-params@5.wast
     binaryen/test/passes/func-metrics.txt
     binaryen/test/passes/func-metrics.wast
     binaryen/test/passes/fuzz-exec_all-features.txt
@@ -943,8 +963,8 @@
     binaryen/test/passes/inlining_enable-tail-call.wast
     binaryen/test/passes/inlining_optimize-level=3.txt
     binaryen/test/passes/inlining_optimize-level=3.wast
-    binaryen/test/passes/instrument-locals_all-features.txt
-    binaryen/test/passes/instrument-locals_all-features.wast
+    binaryen/test/passes/instrument-locals_all-features_disable-typed-function-references.txt
+    binaryen/test/passes/instrument-locals_all-features_disable-typed-function-references.wast
     binaryen/test/passes/instrument-memory.txt
     binaryen/test/passes/instrument-memory.wast
     binaryen/test/passes/instrument-memory64.passes
@@ -967,6 +987,10 @@
     binaryen/test/passes/log-execution.wast
     binaryen/test/passes/memory-packing_all-features.txt
     binaryen/test/passes/memory-packing_all-features.wast
+    binaryen/test/passes/memory-packing_all-features_zero-filled-memory.txt
+    binaryen/test/passes/memory-packing_all-features_zero-filled-memory.wast
+    binaryen/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.txt
+    binaryen/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast
     binaryen/test/passes/merge-blocks.txt
     binaryen/test/passes/merge-blocks.wast
     binaryen/test/passes/merge-blocks_remove-unused-brs.txt
@@ -1017,6 +1041,10 @@
     binaryen/test/passes/O3_print-stack-ir.wast
     binaryen/test/passes/O4_disable-bulk-memory.txt
     binaryen/test/passes/O4_disable-bulk-memory.wast
+    binaryen/test/passes/O_all-features.txt
+    binaryen/test/passes/O_all-features.wast
+    binaryen/test/passes/O_all-features_ignore-implicit-traps.txt
+    binaryen/test/passes/O_all-features_ignore-implicit-traps.wast
     binaryen/test/passes/O_fast-math.txt
     binaryen/test/passes/O_fast-math.wast
     binaryen/test/passes/optimize-added-constants-propagate_low-memory-unused.txt
@@ -1025,14 +1053,20 @@
     binaryen/test/passes/optimize-added-constants_low-memory-unused.wast
     binaryen/test/passes/optimize-instructions_all-features.txt
     binaryen/test/passes/optimize-instructions_all-features.wast
+    binaryen/test/passes/optimize-instructions_fuzz-exec.txt
+    binaryen/test/passes/optimize-instructions_fuzz-exec.wast
     binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.txt
     binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.wast
     binaryen/test/passes/Os_print-stack-ir_all-features.txt
     binaryen/test/passes/Os_print-stack-ir_all-features.wast
     binaryen/test/passes/Oz.txt
     binaryen/test/passes/Oz.wast
+    binaryen/test/passes/Oz_fuzz-exec_all-features.txt
+    binaryen/test/passes/Oz_fuzz-exec_all-features.wast
     binaryen/test/passes/pick-load-signs.txt
     binaryen/test/passes/pick-load-signs.wast
+    binaryen/test/passes/pick-load-signs_all-features.txt
+    binaryen/test/passes/pick-load-signs_all-features.wast
     binaryen/test/passes/post-assemblyscript-finalize.txt
     binaryen/test/passes/post-assemblyscript-finalize.wast
     binaryen/test/passes/post-assemblyscript.txt
@@ -1102,6 +1136,9 @@
     binaryen/test/passes/reverse_dwarf_abbrevs.wasm
     binaryen/test/passes/roundtrip.txt
     binaryen/test/passes/roundtrip.wast
+    binaryen/test/passes/roundtrip_signed.bin.txt
+    binaryen/test/passes/roundtrip_signed.passes
+    binaryen/test/passes/roundtrip_signed.wasm
     binaryen/test/passes/rse_all-features.txt
     binaryen/test/passes/rse_all-features.wast
     binaryen/test/passes/safe-heap_disable-simd.txt
@@ -1113,10 +1150,15 @@
     binaryen/test/passes/safe-heap_enable-threads_enable-simd64.wast
     binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.txt
     binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.wast
+    binaryen/test/passes/safe-heap_start-function.passes
+    binaryen/test/passes/safe-heap_start-function.txt
+    binaryen/test/passes/safe-heap_start-function.wast
     binaryen/test/passes/simplify-globals-optimizing_enable-mutable-globals.txt
     binaryen/test/passes/simplify-globals-optimizing_enable-mutable-globals.wast
     binaryen/test/passes/simplify-globals_all-features.txt
     binaryen/test/passes/simplify-globals_all-features.wast
+    binaryen/test/passes/simplify-globals_all-features_fuzz-exec.txt
+    binaryen/test/passes/simplify-globals_all-features_fuzz-exec.wast
     binaryen/test/passes/simplify-locals-nonesting.txt
     binaryen/test/passes/simplify-locals-nonesting.wast
     binaryen/test/passes/simplify-locals-nostructure.txt
@@ -1133,8 +1175,6 @@
     binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.wast
     binaryen/test/passes/souperify.txt
     binaryen/test/passes/souperify.wast
-    binaryen/test/passes/spill-pointers.txt
-    binaryen/test/passes/spill-pointers.wast
     binaryen/test/passes/ssa-nomerge_enable-simd.txt
     binaryen/test/passes/ssa-nomerge_enable-simd.wast
     binaryen/test/passes/ssa_enable-threads.txt
@@ -1159,7 +1199,8 @@
     binaryen/test/passes/too_much_for_liveness.passes
     binaryen/test/passes/too_much_for_liveness.wasm
     binaryen/test/passes/translate-to-fuzz_all-features.txt
-    binaryen/test/passes/translate-to-fuzz_all-features.wast
+    binaryen/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
+    binaryen/test/passes/translate-to-fuzz_all-features_metrics_noprint.wast
     binaryen/test/passes/trap-mode-clamp.txt
     binaryen/test/passes/trap-mode-clamp.wast
     binaryen/test/passes/trap-mode-js.txt
@@ -1389,12 +1430,10 @@
     binaryen/test/tail-call.wast.from-wast
     binaryen/test/tail-call.wast.fromBinary
     binaryen/test/tail-call.wast.fromBinary.noDebugInfo
-    binaryen/test/threads.asm.js
-    binaryen/test/threads.wasm-only.asm.js
-    binaryen/test/try-body-multiple-insts.wasm
-    binaryen/test/try-body-multiple-insts.wasm.fromBinary
-    binaryen/test/two_sides.asm.js
-    binaryen/test/unit.asm.js
+    binaryen/test/typed-function-references.wast
+    binaryen/test/typed-function-references.wast.from-wast
+    binaryen/test/typed-function-references.wast.fromBinary
+    binaryen/test/typed-function-references.wast.fromBinary.noDebugInfo
     binaryen/test/unit.wast.from-wast
     binaryen/test/unit.wast.fromBinary
     binaryen/test/unit.wast.fromBinary.noDebugInfo
@@ -1417,7 +1456,9 @@
     binaryen/test/unit/input/empty_lld.wat
     binaryen/test/unit/input/exception_handling_target_feature.wasm
     binaryen/test/unit/input/gc_target_feature.wasm
+    binaryen/test/unit/input/hello_world.wat
     binaryen/test/unit/input/mutable_globals_target_feature.wasm
+    binaryen/test/unit/input/random_data.txt
     binaryen/test/unit/input/reference_types_target_feature.wasm
     binaryen/test/unit/input/signext_target_feature.wasm
     binaryen/test/unit/input/simd_target_feature.wasm
@@ -1428,9 +1469,9 @@
     binaryen/test/unit/test_asyncify.py
     binaryen/test/unit/test_datacount.py
     binaryen/test/unit/test_dwarf.py
-    binaryen/test/unit/test_errors.py
     binaryen/test/unit/test_features.py
     binaryen/test/unit/test_finalize.py
+    binaryen/test/unit/test_initial_fuzz.py
     binaryen/test/unit/test_memory_packing.py
     binaryen/test/unit/test_poppy_validation.py
     binaryen/test/unit/test_stack_ir.py
@@ -1442,7 +1483,6 @@
     binaryen/test/unreachable-code.wast.from-wast
     binaryen/test/unreachable-code.wast.fromBinary
     binaryen/test/unreachable-code.wast.fromBinary.noDebugInfo
-    binaryen/test/unreachable-import_wasm-only.asm.js
     binaryen/test/unreachable-instr-type.wast
     binaryen/test/unreachable-instr-type.wast.from-wast
     binaryen/test/unreachable-instr-type.wast.fromBinary
@@ -1453,12 +1493,10 @@
     binaryen/test/untaken-br_if.wast.from-wast
     binaryen/test/untaken-br_if.wast.fromBinary
     binaryen/test/untaken-br_if.wast.fromBinary.noDebugInfo
-    binaryen/test/use-import-and-drop.asm.js
     binaryen/test/validator/invalid_export.wast
     binaryen/test/validator/invalid_import.wast
     binaryen/test/validator/invalid_number.wast
     binaryen/test/validator/invalid_return.wast
-    binaryen/test/wasm-only.asm.js
     binaryen/test/wasm2asm.asserts.js
     binaryen/test/wasm2asm.traps.js
     binaryen/test/wasm2js.asserts.js
@@ -1990,6 +2028,7 @@
         binaryen/src/ir/ExpressionAnalyzer.cpp
         binaryen/src/ir/ExpressionManipulator.cpp
         binaryen/src/ir/LocalGraph.cpp
+        binaryen/src/ir/module-splitting.cpp
         binaryen/src/ir/ReFinalize.cpp
         binaryen/src/ir/stack-utils.cpp
         binaryen/src/passes/AlignmentLowering.cpp
@@ -2008,7 +2047,6 @@
         binaryen/src/passes/DuplicateFunctionElimination.cpp
         binaryen/src/passes/DuplicateImportElimination.cpp
         binaryen/src/passes/DWARF.cpp
-        binaryen/src/passes/EmscriptenPIC.cpp
         binaryen/src/passes/ExtractFunction.cpp
         binaryen/src/passes/Flatten.cpp
         binaryen/src/passes/FuncCastEmulation.cpp
@@ -2022,6 +2060,7 @@
         binaryen/src/passes/LocalCSE.cpp
         binaryen/src/passes/LogExecution.cpp
         binaryen/src/passes/LoopInvariantCodeMotion.cpp
+        binaryen/src/passes/Memory64Lowering.cpp
         binaryen/src/passes/MemoryPacking.cpp
         binaryen/src/passes/MergeBlocks.cpp
         binaryen/src/passes/MergeLocals.cpp
@@ -2049,14 +2088,12 @@
         binaryen/src/passes/RemoveUnusedNames.cpp
         binaryen/src/passes/ReorderFunctions.cpp
         binaryen/src/passes/ReorderLocals.cpp
-        binaryen/src/passes/ReplaceStackPointer.cpp
         binaryen/src/passes/ReReloop.cpp
         binaryen/src/passes/RoundTrip.cpp
         binaryen/src/passes/SafeHeap.cpp
         binaryen/src/passes/SimplifyGlobals.cpp
         binaryen/src/passes/SimplifyLocals.cpp
         binaryen/src/passes/Souperify.cpp
-        binaryen/src/passes/SpillPointers.cpp
         binaryen/src/passes/SSAify.cpp
         binaryen/src/passes/StackCheck.cpp
         binaryen/src/passes/StackIR.cpp
diff --git a/binaryen/CHANGELOG.md b/binaryen/CHANGELOG.md
--- a/binaryen/CHANGELOG.md
+++ b/binaryen/CHANGELOG.md
@@ -15,6 +15,21 @@
 Current Trunk
 -------------
 
+- `RefFunc` C and JS API constructors (`BinaryenRefFunc` and `ref.func`
+  respectively) now take an extra `type` parameter, similar to `RefNull`. This
+  is necessary for typed function references support.
+- JS API functions for atomic notify/wait instructions are renamed.
+  - `module.atomic.notify` -> `module.memory.atomic.notify`
+  - `module.i32.atomic.wait` -> `module.memory.atomic.wait32`
+  - `module.i64.atomic.wait` -> `module.memory.atomic.wait64`
+- Remove old/broken SpollPointers pass.  This pass: Spills values that might be
+  pointers to the C stack. This allows Boehm-style GC to see them properly.
+  This can be revived if needed from git history (#3261).
+- Make `NUM_PARAMS` in `FuncCastEmulation` a runtime configuration option named
+  `max-func-params`. This defaults to the original value of 16.
+- `BinaryenGetFunction`, `BinaryenGetGlobal` and `BinaryenGetEvent` now return
+  `NULL` instead of aborting when the respective element does not yet exist.
+
 v98
 ---
 
diff --git a/binaryen/CMakeLists.txt b/binaryen/CMakeLists.txt
--- a/binaryen/CMakeLists.txt
+++ b/binaryen/CMakeLists.txt
@@ -82,7 +82,7 @@
     set(_install_name_dir INSTALL_NAME_DIR "@rpath")
     set(_install_rpath "@loader_path/../lib")
   elseif(UNIX)
-    set(_install_rpath "\$ORIGIN/../lib")
+    set(_install_rpath "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
     if(${CMAKE_SYSTEM_NAME} MATCHES "(FreeBSD|DragonFly)")
       set_property(TARGET ${name} APPEND_STRING PROPERTY
                    LINK_FLAGS " -Wl,-z,origin ")
@@ -214,6 +214,7 @@
   add_compile_flag("-Wextra")
   add_compile_flag("-Wno-unused-parameter")
   add_compile_flag("-fno-omit-frame-pointer")
+  add_compile_flag("-fno-rtti")
   # TODO(https://github.com/WebAssembly/binaryen/pull/2314): Remove these two
   # flags once we resolve the issue.
   add_compile_flag("-Wno-implicit-int-float-conversion")
@@ -221,6 +222,7 @@
   add_compile_flag("-Wswitch") # we explicitly expect this in the code
   if(WIN32)
     add_compile_flag("-D_GNU_SOURCE")
+    add_compile_flag("-D__STDC_FORMAT_MACROS")
     add_link_flag("-Wl,--stack,8388608")
   elseif(NOT EMSCRIPTEN)
     add_compile_flag("-fPIC")
@@ -276,6 +278,9 @@
 add_subdirectory(src/wasm)
 add_subdirectory(third_party)
 
+# Configure lit tests
+add_subdirectory(test/lit)
+
 # Object files
 set(binaryen_objs
     $<TARGET_OBJECTS:passes>
@@ -331,6 +336,7 @@
 binaryen_add_executable(wasm-dis src/tools/wasm-dis.cpp)
 binaryen_add_executable(wasm-ctor-eval src/tools/wasm-ctor-eval.cpp)
 binaryen_add_executable(wasm-reduce src/tools/wasm-reduce.cpp)
+binaryen_add_executable(wasm-split src/tools/wasm-split.cpp)
 
 
 # binaryen.js
@@ -388,3 +394,5 @@
   set_property(TARGET binaryen_js PROPERTY CXX_STANDARD_REQUIRED ON)
   install(TARGETS binaryen_js DESTINATION ${CMAKE_INSTALL_BINDIR})
 endif()
+
+configure_file(scripts/binaryen-lit.in ${CMAKE_BINARY_DIR}/bin/binaryen-lit @ONLY)
diff --git a/binaryen/auto_update_tests.py b/binaryen/auto_update_tests.py
--- a/binaryen/auto_update_tests.py
+++ b/binaryen/auto_update_tests.py
@@ -29,27 +29,14 @@
 
 def update_example_tests():
     print('\n[ checking example testcases... ]\n')
-    for t in shared.get_tests(shared.get_test_dir('example')):
-        basename = os.path.basename(t)
+    for src in shared.get_tests(shared.get_test_dir('example')):
+        basename = os.path.basename(src)
         output_file = os.path.join(shared.options.binaryen_bin, 'example')
         libdir = os.path.join(shared.BINARYEN_INSTALL_DIR, 'lib')
         cmd = ['-I' + os.path.join(shared.options.binaryen_root, 'src'), '-g', '-pthread', '-o', output_file]
-        if t.endswith('.txt'):
-            # check if there is a trace in the file, if so, we should build it
-            out = subprocess.Popen([os.path.join(shared.options.binaryen_root, 'scripts', 'clean_c_api_trace.py'), t], stdout=subprocess.PIPE).communicate()[0]
-            if len(out) == 0:
-                print('  (no trace in ', basename, ')')
-                continue
-            print('  (will check trace in ', basename, ')')
-            src = 'trace.cpp'
-            with open(src, 'wb') as o:
-                o.write(out)
-            expected = t + '.txt'
-        else:
-            src = t
-            expected = os.path.splitext(t)[0] + '.txt'
         if not src.endswith(('.c', '.cpp')):
             continue
+        expected = os.path.splitext(src)[0] + '.txt'
         # windows + gcc will need some work
         if shared.skip_if_on_windows('gcc'):
             return
diff --git a/binaryen/check.py b/binaryen/check.py
--- a/binaryen/check.py
+++ b/binaryen/check.py
@@ -29,11 +29,6 @@
 from scripts.test import wasm_opt
 
 
-if shared.options.interpreter:
-    print('[ using wasm interpreter at "%s" ]' % shared.options.interpreter)
-    assert os.path.exists(shared.options.interpreter), 'interpreter not found'
-
-
 def get_changelog_version():
     with open(os.path.join(shared.options.binaryen_root, 'CHANGELOG.md')) as f:
         lines = f.readlines()
@@ -47,7 +42,7 @@
 def run_help_tests():
     print('[ checking --help is useful... ]\n')
 
-    not_executable_suffix = ['.txt', '.js', '.ilk', '.pdb', '.dll', '.wasm', '.manifest']
+    not_executable_suffix = ['.txt', '.js', '.ilk', '.pdb', '.dll', '.wasm', '.manifest', 'binaryen-lit']
     bin_files = [os.path.join(shared.options.binaryen_bin, f) for f in os.listdir(shared.options.binaryen_bin)]
     executables = [f for f in bin_files if os.path.isfile(f) and not any(f.endswith(s) for s in not_executable_suffix)]
     executables = sorted(executables)
@@ -291,37 +286,24 @@
 
     for t in sorted(os.listdir(shared.get_test_dir('example'))):
         output_file = 'example'
-        cmd = ['-I' + os.path.join(shared.options.binaryen_root, 'src'), '-g', '-pthread', '-o', output_file]
-        if t.endswith('.txt'):
-            # check if there is a trace in the file, if so, we should build it
-            out = subprocess.check_output([os.path.join(shared.options.binaryen_root, 'scripts', 'clean_c_api_trace.py'), os.path.join(shared.get_test_dir('example'), t)])
-            if len(out) == 0:
-                print('  (no trace in ', t, ')')
-                continue
-            print('  (will check trace in ', t, ')')
-            src = 'trace.cpp'
-            with open(src, 'wb') as o:
-                o.write(out)
-            expected = os.path.join(shared.get_test_dir('example'), t + '.txt')
-        else:
-            src = os.path.join(shared.get_test_dir('example'), t)
-            expected = os.path.join(shared.get_test_dir('example'), '.'.join(t.split('.')[:-1]) + '.txt')
-        if src.endswith(('.c', '.cpp')):
-            # build the C file separately
-            libpath = os.path.join(os.path.dirname(shared.options.binaryen_bin),  'lib')
-            extra = [shared.NATIVECC, src, '-c', '-o', 'example.o',
-                     '-I' + os.path.join(shared.options.binaryen_root, 'src'), '-g', '-L' + libpath, '-pthread']
-            if src.endswith('.cpp'):
-                extra += ['-std=c++' + str(shared.cxx_standard)]
-            if os.environ.get('COMPILER_FLAGS'):
-                for f in os.environ.get('COMPILER_FLAGS').split(' '):
-                    extra.append(f)
-            print('build: ', ' '.join(extra))
-            subprocess.check_call(extra)
-            # Link against the binaryen C library DSO, using an executable-relative rpath
-            cmd = ['example.o', '-L' + libpath, '-lbinaryen'] + cmd + ['-Wl,-rpath,' + libpath]
-        else:
+        cmd = ['-I' + os.path.join(shared.options.binaryen_root, 't'), '-g', '-pthread', '-o', output_file]
+        if not t.endswith(('.c', '.cpp')):
             continue
+        src = os.path.join(shared.get_test_dir('example'), t)
+        expected = os.path.join(shared.get_test_dir('example'), '.'.join(t.split('.')[:-1]) + '.txt')
+        # build the C file separately
+        libpath = shared.options.binaryen_lib
+        extra = [shared.NATIVECC, src, '-c', '-o', 'example.o',
+                 '-I' + os.path.join(shared.options.binaryen_root, 'src'), '-g', '-L' + libpath, '-pthread']
+        if src.endswith('.cpp'):
+            extra += ['-std=c++' + str(shared.cxx_standard)]
+        if os.environ.get('COMPILER_FLAGS'):
+            for f in os.environ.get('COMPILER_FLAGS').split(' '):
+                extra.append(f)
+        print('build: ', ' '.join(extra))
+        subprocess.check_call(extra)
+        # Link against the binaryen C library DSO, using an executable-relative rpath
+        cmd = ['example.o', '-L' + libpath, '-lbinaryen'] + cmd + ['-Wl,-rpath,' + libpath]
         print('  ', t, src, expected)
         if os.environ.get('COMPILER_FLAGS'):
             for f in os.environ.get('COMPILER_FLAGS').split(' '):
@@ -346,6 +328,18 @@
         raise Exception("unittest failed")
 
 
+def run_lit():
+    lit_script = os.path.join(shared.options.binaryen_bin, 'binaryen-lit')
+    lit_tests = os.path.join(shared.options.binaryen_root, 'test', 'lit')
+    # lit expects to be run as its own executable
+    cmd = [sys.executable, lit_script, lit_tests, '-vv']
+    result = subprocess.run(cmd)
+    if result.returncode != 0:
+        shared.num_failures += 1
+    if shared.options.abort_on_first_failure and shared.num_failures:
+        raise Exception("lit test failed")
+
+
 TEST_SUITES = OrderedDict([
     ('help-messages', run_help_tests),
     ('wasm-opt', wasm_opt.test_wasm_opt),
@@ -363,6 +357,7 @@
     ('unit', run_unittest),
     ('binaryenjs', binaryenjs.test_binaryen_js),
     ('binaryenjs_wasm', binaryenjs.test_binaryen_wasm),
+    ('lit', run_lit),
 ])
 
 
diff --git a/binaryen/requirements-dev.txt b/binaryen/requirements-dev.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/requirements-dev.txt
@@ -0,0 +1,8 @@
+# These requirements are only needed for developers who want to run the test
+# suite or flake8, not for end users.
+
+# Install with `pip3 install -r requirements-dev.txt`
+
+flake8==3.7.8
+filecheck==0.0.17
+lit==0.11.0.post1
diff --git a/binaryen/scripts/binaryen-lit.in b/binaryen/scripts/binaryen-lit.in
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/binaryen-lit.in
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+#
+# 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.
+
+import os
+from lit.main import main
+
+# A simple wrapper around `lit` test running.   Loosely based on
+# llvm's llvm-lit script
+
+builtin_parameters = {
+    'config_map': {
+        os.path.normcase(os.path.normpath('@CMAKE_SOURCE_DIR@/test/lit/lit.cfg.py')):
+        os.path.normcase(os.path.normpath('@CMAKE_BINARY_DIR@/test/lit/lit.site.cfg.py'))
+    }
+}
+
+print(builtin_parameters)
+
+if __name__ == '__main__':
+    main(builtin_parameters)
diff --git a/binaryen/scripts/clean_c_api_trace.py b/binaryen/scripts/clean_c_api_trace.py
deleted file mode 100644
--- a/binaryen/scripts/clean_c_api_trace.py
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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.
-
-"""Cleans up output from the C api, makes a runnable C file
-"""
-
-import sys
-
-trace = open(sys.argv[1]).read()
-
-start = trace.find('// beginning a Binaryen API trace')
-end = trace.rfind('// ending a Binaryen API trace')
-if start >= 0:
-    trace = trace[start:end]
-
-    while 1:
-        start = trace.find('\n(')
-        if start < 0:
-            break
-        end = trace.find('\n)', start + 1)
-        assert end > 0
-        trace = trace[:start] + trace[end + 2:]
-
-    print(trace)
diff --git a/binaryen/scripts/fuzz_opt.py b/binaryen/scripts/fuzz_opt.py
--- a/binaryen/scripts/fuzz_opt.py
+++ b/binaryen/scripts/fuzz_opt.py
@@ -28,7 +28,9 @@
 import traceback
 
 from test import shared
+from test import support
 
+
 assert sys.version_info.major == 3, 'requires Python 3!'
 
 # parameters
@@ -68,9 +70,10 @@
     return random.randint(INPUT_SIZE_MIN, 2 * INPUT_SIZE_MEAN - INPUT_SIZE_MIN)
 
 
-def run(cmd):
-    print(' '.join(cmd))
-    return subprocess.check_output(cmd, text=True)
+def run(cmd, stderr=None, silent=False):
+    if not silent:
+        print(' '.join(cmd))
+    return subprocess.check_output(cmd, stderr=stderr, text=True)
 
 
 def run_unchecked(cmd):
@@ -102,12 +105,11 @@
 def randomize_feature_opts():
     global FEATURE_OPTS
     FEATURE_OPTS = CONSTANT_FEATURE_OPTS[:]
-    # half the time apply all the possible opts. this lets all test runners work at max
-    # capacity at least half the time, as otherwise if they need almost all the opts, the
-    # chance of getting them is exponentially small.
-    if random.random() < 0.5:
+    # 1/3 the time apply all the possible opts, 1/3 none of them, to maximize
+    # coverage both ways, and 1/3 pick each one randomly
+    if random.random() < 0.33333:
         FEATURE_OPTS += POSSIBLE_FEATURE_OPTS
-    else:
+    elif random.random() < 0.5:
         for possible in POSSIBLE_FEATURE_OPTS:
             if random.random() < 0.5:
                 FEATURE_OPTS.append(possible)
@@ -116,15 +118,19 @@
     print('randomized feature opts:', ' '.join(FEATURE_OPTS))
 
 
-FUZZ_OPTS = None
-NANS = None
-OOB = None
-LEGALIZE = None
-ORIGINAL_V8_OPTS = shared.V8_OPTS[:]
+def randomize_fuzz_settings():
+    # a list of the optimizations to run on the wasm
+    global FUZZ_OPTS
 
+    # a boolean whether NaN values are allowed, or we de-NaN them
+    global NANS
 
-def randomize_fuzz_settings():
-    global FUZZ_OPTS, NANS, OOB, LEGALIZE
+    # a boolean whether out of bounds operations are allowed, or we bounds-enforce them
+    global OOB
+
+    # a boolean whether we legalize the wasm for JS
+    global LEGALIZE
+
     FUZZ_OPTS = []
     if random.random() < 0.5:
         NANS = True
@@ -141,25 +147,93 @@
         FUZZ_OPTS += ['--legalize-js-interface']
     else:
         LEGALIZE = False
-    extra_v8_opts = []
-    # 50% of the time test v8 normally, that is, the same way it runs in
-    # production (which as of 07/15/2020 means baseline, then tier up to
-    # optimizing, but that may change in the future).
+    print('randomized settings (NaNs, OOB, legalize):', NANS, OOB, LEGALIZE)
+
+
+IMPORTANT_INITIAL_CONTENTS = [
+    os.path.join('passes', 'optimize-instructions_all-features.wast'),
+    os.path.join('passes', 'optimize-instructions_fuzz-exec.wast'),
+]
+IMPORTANT_INITIAL_CONTENTS = [os.path.join(shared.get_test_dir('.'), t) for t in IMPORTANT_INITIAL_CONTENTS]
+
+
+def pick_initial_contents():
+    # if we use an initial wasm file's contents as the basis for the
+    # fuzzing, then that filename, or None if we start entirely from scratch
+    global INITIAL_CONTENTS
+
+    INITIAL_CONTENTS = None
+    # half the time don't use any initial contents
     if random.random() < 0.5:
-        # test either the optimizing compiler or the baseline compiler, with
-        # equal probability. it's useful to do this because the normal tier-up
-        # mode does not check them both equally (typically baseline does not get
-        # enough testing, as we quickly leave it), and also because the tiering
-        # up is nondeterministic (when optimized code becomes ready, we switch
-        # to it)
-        if random.random() < 0.5:
-            extra_v8_opts += ['--no-liftoff']
-        else:
-            extra_v8_opts += ['--liftoff', '--no-wasm-tier-up']
-    shared.V8_OPTS = ORIGINAL_V8_OPTS + extra_v8_opts
-    print('randomized settings (NaNs, OOB, legalize, extra V8_OPTS):', NANS, OOB, LEGALIZE, extra_v8_opts)
+        return
+    # some of the time use initial contents that are known to be especially
+    # important
+    if random.random() < 0.5:
+        test_name = random.choice(IMPORTANT_INITIAL_CONTENTS)
+    else:
+        test_name = random.choice(all_tests)
+    print('initial contents:', test_name)
+    assert os.path.exists(test_name)
+    # tests that check validation errors are not helpful for us
+    if '.fail.' in test_name:
+        print('initial contents is just a .fail test')
+        return
+    if os.path.basename(test_name) in [
+        # contains too many segments to run in a wasm VM
+        'limit-segments_disable-bulk-memory.wast',
+        # https://github.com/WebAssembly/binaryen/issues/3203
+        'simd.wast',
+        # corner cases of escaping of names is not interesting
+        'names.wast',
+        # huge amount of locals that make it extremely slow
+        'too_much_for_liveness.wasm'
+    ]:
+        print('initial contents is disallowed')
+        return
 
+    if test_name.endswith('.wast'):
+        # this can contain multiple modules, pick one
+        split_parts = support.split_wast(test_name)
+        if len(split_parts) > 1:
+            index = random.randint(0, len(split_parts) - 1)
+            chosen = split_parts[index]
+            module, asserts = chosen
+            if not module:
+                # there is no module in this choice (just asserts), ignore it
+                print('initial contents has no module')
+                return
+            test_name = 'initial.wat'
+            with open(test_name, 'w') as f:
+                f.write(module)
+            print('  picked submodule %d from multi-module wast' % index)
 
+    global FEATURE_OPTS
+    FEATURE_OPTS += [
+        # has not been enabled in the fuzzer yet
+        '--disable-exception-handling',
+        # has not been fuzzed in general yet
+        '--disable-memory64',
+        # has not been fuzzed in general yet
+        '--disable-gc',
+        # DWARF is incompatible with multivalue atm; it's more important to
+        # fuzz multivalue since we aren't actually fuzzing DWARF here
+        '--strip-dwarf',
+    ]
+
+    # the given wasm may not work with the chosen feature opts. for example, if
+    # we pick atomics.wast but want to run with --disable-atomics, then we'd
+    # error. test the wasm.
+    try:
+        run([in_bin('wasm-opt'), test_name] + FEATURE_OPTS,
+            stderr=subprocess.PIPE,
+            silent=True)
+    except Exception:
+        print('(initial contents not valid for features, ignoring)')
+        return
+
+    INITIAL_CONTENTS = test_name
+
+
 # Test outputs we want to ignore are marked this way.
 IGNORE = '[binaryen-fuzzer-ignore]'
 
@@ -302,14 +376,27 @@
         del os.environ['BINARYEN_MAX_INTERPRETER_DEPTH']
 
 
-def run_d8_js(js, args=[]):
-    return run_vm([shared.V8] + shared.V8_OPTS + [js] + (['--'] if args else []) + args)
+V8_LIFTOFF_ARGS = ['--liftoff', '--no-wasm-tier-up']
 
 
-def run_d8_wasm(wasm):
-    return run_d8_js(in_binaryen('scripts', 'fuzz_shell.js'), [wasm])
+# default to running with liftoff enabled, because we need to pick either
+# liftoff or turbofan for consistency (otherwise running the same command twice
+# may have different results due to NaN nondeterminism), and liftoff is faster
+# for small things
+def run_d8_js(js, args=[], liftoff=True):
+    cmd = [shared.V8] + shared.V8_OPTS
+    if liftoff:
+        cmd += V8_LIFTOFF_ARGS
+    cmd += [js]
+    if args:
+        cmd += ['--'] + args
+    return run_vm(cmd)
 
 
+def run_d8_wasm(wasm, liftoff=True):
+    return run_d8_js(in_binaryen('scripts', 'fuzz_shell.js'), [wasm], liftoff=liftoff)
+
+
 class TestCaseHandler:
     # how frequent this handler will be run. 1 means always run it, 0.5 means half the
     # time
@@ -335,19 +422,6 @@
         return self.num_runs
 
 
-# Run VMs and compare results
-
-class VM:
-    def __init__(self, name, run, can_compare_to_self, can_compare_to_others):
-        self.name = name
-        self.run = run
-        self.can_compare_to_self = can_compare_to_self
-        self.can_compare_to_others = can_compare_to_others
-
-    def can_run(self, wasm):
-        return True
-
-
 # Fuzz the interpreter with --fuzz-exec.
 class FuzzExec(TestCaseHandler):
     frequency = 1
@@ -362,23 +436,57 @@
     def __init__(self):
         super(CompareVMs, self).__init__()
 
-        def byn_run(wasm):
-            return run_bynterp(wasm, ['--fuzz-exec-before'])
+        class BinaryenInterpreter:
+            name = 'binaryen interpreter'
 
-        def v8_run(wasm):
-            run([in_bin('wasm-opt'), wasm, '--emit-js-wrapper=' + wasm + '.js'] + FEATURE_OPTS)
-            return run_vm([shared.V8, wasm + '.js'] + shared.V8_OPTS + ['--', wasm])
+            def run(self, wasm):
+                return run_bynterp(wasm, ['--fuzz-exec-before'])
 
-        def yes():
-            return True
+            def can_run(self, wasm):
+                return True
 
-        def if_legal_and_no_nans():
-            return LEGALIZE and not NANS
+            def can_compare_to_self(self):
+                return True
 
-        def if_no_nans():
-            return not NANS
+            def can_compare_to_others(self):
+                return True
 
-        class Wasm2C(VM):
+        class D8:
+            name = 'd8'
+
+            def run(self, wasm, extra_d8_flags=[]):
+                run([in_bin('wasm-opt'), wasm, '--emit-js-wrapper=' + wasm + '.js'] + FEATURE_OPTS)
+                return run_vm([shared.V8, wasm + '.js'] + shared.V8_OPTS + extra_d8_flags + ['--', wasm])
+
+            def can_run(self, wasm):
+                # INITIAL_CONTENT is disallowed because some initial spec testcases
+                # have names that require mangling, see
+                # https://github.com/WebAssembly/binaryen/pull/3216
+                return not INITIAL_CONTENTS
+
+            def can_compare_to_self(self):
+                # With nans, VM differences can confuse us, so only very simple VMs
+                # can compare to themselves after opts in that case.
+                return not NANS
+
+            def can_compare_to_others(self):
+                # If not legalized, the JS will fail immediately, so no point to
+                # compare to others.
+                return LEGALIZE and not NANS
+
+        class D8Liftoff(D8):
+            name = 'd8_liftoff'
+
+            def run(self, wasm):
+                return super(D8Liftoff, self).run(wasm, extra_d8_flags=V8_LIFTOFF_ARGS)
+
+        class D8TurboFan(D8):
+            name = 'd8_turbofan'
+
+            def run(self, wasm):
+                return super(D8TurboFan, self).run(wasm, extra_d8_flags=['--no-liftoff'])
+
+        class Wasm2C:
             name = 'wasm2c'
 
             def __init__(self):
@@ -433,7 +541,11 @@
             def run(self, wasm):
                 run([in_bin('wasm-opt'), wasm, '--emit-wasm2c-wrapper=main.c'] + FEATURE_OPTS)
                 run(['wasm2c', wasm, '-o', 'wasm.c'])
-                compile_cmd = ['emcc', 'main.c', 'wasm.c', os.path.join(self.wasm2c_dir, 'wasm-rt-impl.c'), '-I' + self.wasm2c_dir, '-lm']
+                compile_cmd = ['emcc', 'main.c', 'wasm.c',
+                               os.path.join(self.wasm2c_dir, 'wasm-rt-impl.c'),
+                               '-I' + self.wasm2c_dir,
+                               '-lm',
+                               '-s', 'ALLOW_MEMORY_GROWTH']
                 # disable the signal handler: emcc looks like unix, but wasm has
                 # no signals
                 compile_cmd += ['-DWASM_RT_MEMCHECK_SIGNAL_HANDLER=0']
@@ -464,14 +576,8 @@
                 # NaNs can differ from wasm VMs
                 return not NANS
 
-        self.vms = [
-            VM('binaryen interpreter', byn_run,    can_compare_to_self=yes,        can_compare_to_others=yes),
-            # with nans, VM differences can confuse us, so only very simple VMs can compare to themselves after opts in that case.
-            # if not legalized, the JS will fail immediately, so no point to compare to others
-            VM('d8',                   v8_run,     can_compare_to_self=if_no_nans, can_compare_to_others=if_legal_and_no_nans),
-            Wasm2C(),
-            Wasm2C2Wasm(),
-        ]
+        self.vms = [BinaryenInterpreter(), D8(), D8Liftoff(), D8TurboFan(),
+                    Wasm2C(), Wasm2C2Wasm()]
 
     def handle_pair(self, input, before_wasm, after_wasm, opts):
         before = self.run_vms(before_wasm)
@@ -483,6 +589,7 @@
         vm_results = {}
         for vm in self.vms:
             if vm.can_run(wasm):
+                print(f'[CompareVMs] running {vm.name}')
                 vm_results[vm] = fix_output(vm.run(wasm))
 
         # compare between the vms on this specific input
@@ -635,6 +742,13 @@
         return run_vm([shared.NODEJS, js_file, 'a.wasm'])
 
     def can_run_on_feature_opts(self, feature_opts):
+        # TODO: properly handle memory growth. right now the wasm2js handler
+        # uses --emscripten which assumes the Memory is created before, and
+        # wasm2js.js just starts with a size of 1 and no limit. We should switch
+        # to non-emscripten mode or adding memory information, or check
+        # specifically for growth here
+        if INITIAL_CONTENTS:
+            return False
         return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-threads', '--disable-bulk-memory', '--disable-nontrapping-float-to-int', '--disable-tail-call', '--disable-sign-ext', '--disable-reference-types', '--disable-multivalue', '--disable-gc']])
 
 
@@ -692,6 +806,15 @@
         return all([x in feature_opts for x in ['--disable-exception-handling', '--disable-simd', '--disable-tail-call', '--disable-reference-types', '--disable-multivalue', '--disable-gc']])
 
 
+# Check that the text format round-trips without error.
+class RoundtripText(TestCaseHandler):
+    frequency = 0.05
+
+    def handle(self, wasm):
+        run([in_bin('wasm-dis'), wasm, '-o', 'a.wast'])
+        run([in_bin('wasm-opt'), 'a.wast'] + FEATURE_OPTS)
+
+
 # The global list of all test case handlers
 testcase_handlers = [
     FuzzExec(),
@@ -699,14 +822,29 @@
     CheckDeterminism(),
     Wasm2JS(),
     Asyncify(),
+    RoundtripText()
 ]
 
 
+test_suffixes = ['*.wasm', '*.wast', '*.wat']
+core_tests = shared.get_tests(shared.get_test_dir('.'), test_suffixes)
+passes_tests = shared.get_tests(shared.get_test_dir('passes'), test_suffixes)
+spec_tests = shared.get_tests(shared.get_test_dir('spec'), test_suffixes)
+wasm2js_tests = shared.get_tests(shared.get_test_dir('wasm2js'), test_suffixes)
+lld_tests = shared.get_tests(shared.get_test_dir('lld'), test_suffixes)
+unit_tests = shared.get_tests(shared.get_test_dir(os.path.join('unit', 'input')), test_suffixes)
+all_tests = core_tests + passes_tests + spec_tests + wasm2js_tests + lld_tests + unit_tests
+
+
 # Do one test, given an input file for -ttf and some optimizations to run
-def test_one(random_input, opts, given_wasm):
+def test_one(random_input, given_wasm):
     randomize_pass_debug()
     randomize_feature_opts()
     randomize_fuzz_settings()
+    pick_initial_contents()
+
+    opts = randomize_opt_flags()
+    print('randomized opts:', ' '.join(opts))
     print()
 
     if given_wasm:
@@ -719,6 +857,8 @@
         # emit the target features section so that reduction can work later,
         # without needing to specify the features
         generate_command = [in_bin('wasm-opt'), random_input, '-ttf', '-o', 'a.wasm', '--emit-target-features'] + FUZZ_OPTS + FEATURE_OPTS
+        if INITIAL_CONTENTS:
+            generate_command += ['--initial-fuzz=' + INITIAL_CONTENTS]
         if PRINT_WATS:
             printed = run(generate_command + ['--print'])
             with open('a.printed.wast', 'w') as f:
@@ -840,10 +980,16 @@
     # core opts
     while 1:
         choice = random.choice(opt_choices)
-        if '--flatten' in choice:
+        if '--flatten' in choice or '-O4' in choice:
             if has_flatten:
                 print('avoiding multiple --flatten in a single command, due to exponential overhead')
                 continue
+            if '--disable-exception-handling' not in FEATURE_OPTS:
+                print('avoiding --flatten due to exception catching which does not support it yet')
+                continue
+            if INITIAL_CONTENTS and os.path.getsize(INITIAL_CONTENTS) > 2000:
+                print('avoiding --flatten due using a large amount of initial contents, which may blow up')
+                continue
             else:
                 has_flatten = True
         flag_groups.append(choice)
@@ -925,10 +1071,13 @@
         with open(raw_input_data, 'wb') as f:
             f.write(bytes([random.randint(0, 255) for x in range(input_size)]))
         assert os.path.getsize(raw_input_data) == input_size
-        opts = randomize_opt_flags()
-        print('randomized opts:', ' '.join(opts))
+        # remove the generated wasm file, so that we can tell if the fuzzer
+        # fails to create one
+        if os.path.exists('a.wasm'):
+            os.remove('a.wasm')
+        # run an iteration of the fuzzer
         try:
-            total_wasm_size += test_one(raw_input_data, opts, given_wasm)
+            total_wasm_size += test_one(raw_input_data, given_wasm)
         except KeyboardInterrupt:
             print('(stopping by user request)')
             break
@@ -953,6 +1102,26 @@
             # is likely to be called within wasm-reduce script itself, so
             # original.wasm and reduce.sh should not be overwritten.
             if not given_wasm:
+                # We can't do this if a.wasm doesn't exist, which can be the
+                # case if we failed to even generate the wasm.
+                if not os.path.exists('a.wasm'):
+                    print('''\
+================================================================================
+You found a bug in the fuzzer itself! It failed to generate a valid wasm file
+from the random input. Please report it with
+
+  seed: %(seed)d
+
+and the exact version of Binaryen you found it on, plus the exact Python
+version (hopefully deterministic random numbers will be identical).
+
+You can run that testcase again with "fuzz_opt.py %(seed)d"
+
+(We can't automatically reduce this testcase since we can only run the reducer
+on valid wasm files.)
+================================================================================
+                ''' % {'seed': seed})
+                    break
                 # show some useful info about filing a bug and reducing the
                 # testcase (to make reduction simple, save "original.wasm" on
                 # the side, so that we can autoreduce using the name "a.wasm"
diff --git a/binaryen/scripts/gen-s-parser.py b/binaryen/scripts/gen-s-parser.py
--- a/binaryen/scripts/gen-s-parser.py
+++ b/binaryen/scripts/gen-s-parser.py
@@ -201,9 +201,9 @@
     ("i64.extend16_s",      "makeUnary(s, UnaryOp::ExtendS16Int64)"),
     ("i64.extend32_s",      "makeUnary(s, UnaryOp::ExtendS32Int64)"),
     # atomic instructions
-    ("atomic.notify",           "makeAtomicNotify(s)"),
-    ("i32.atomic.wait",         "makeAtomicWait(s, Type::i32)"),
-    ("i64.atomic.wait",         "makeAtomicWait(s, Type::i64)"),
+    ("memory.atomic.notify",    "makeAtomicNotify(s)"),
+    ("memory.atomic.wait32",    "makeAtomicWait(s, Type::i32)"),
+    ("memory.atomic.wait64",    "makeAtomicWait(s, Type::i64)"),
     ("atomic.fence",            "makeAtomicFence(s)"),
     ("i32.atomic.load8_u",      "makeLoad(s, Type::i32, /*isAtomic=*/true)"),
     ("i32.atomic.load16_u",     "makeLoad(s, Type::i32, /*isAtomic=*/true)"),
@@ -332,6 +332,7 @@
     ("i32x4.le_u",           "makeBinary(s, BinaryOp::LeUVecI32x4)"),
     ("i32x4.ge_s",           "makeBinary(s, BinaryOp::GeSVecI32x4)"),
     ("i32x4.ge_u",           "makeBinary(s, BinaryOp::GeUVecI32x4)"),
+    ("i64x2.eq",             "makeBinary(s, BinaryOp::EqVecI64x2)"),
     ("f32x4.eq",             "makeBinary(s, BinaryOp::EqVecF32x4)"),
     ("f32x4.ne",             "makeBinary(s, BinaryOp::NeVecF32x4)"),
     ("f32x4.lt",             "makeBinary(s, BinaryOp::LtVecF32x4)"),
@@ -350,6 +351,19 @@
     ("v128.xor",             "makeBinary(s, BinaryOp::XorVec128)"),
     ("v128.andnot",          "makeBinary(s, BinaryOp::AndNotVec128)"),
     ("v128.bitselect",       "makeSIMDTernary(s, SIMDTernaryOp::Bitselect)"),
+    ("v8x16.signselect",     "makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec8x16)"),
+    ("v16x8.signselect",     "makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec16x8)"),
+    ("v32x4.signselect",     "makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec32x4)"),
+    ("v64x2.signselect",     "makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec64x2)"),
+    ("v128.load8_lane",      "makeSIMDLoadStoreLane(s, LoadLaneVec8x16)"),
+    ("v128.load16_lane",     "makeSIMDLoadStoreLane(s, LoadLaneVec16x8)"),
+    ("v128.load32_lane",     "makeSIMDLoadStoreLane(s, LoadLaneVec32x4)"),
+    ("v128.load64_lane",     "makeSIMDLoadStoreLane(s, LoadLaneVec64x2)"),
+    ("v128.store8_lane",     "makeSIMDLoadStoreLane(s, StoreLaneVec8x16)"),
+    ("v128.store16_lane",    "makeSIMDLoadStoreLane(s, StoreLaneVec16x8)"),
+    ("v128.store32_lane",    "makeSIMDLoadStoreLane(s, StoreLaneVec32x4)"),
+    ("v128.store64_lane",    "makeSIMDLoadStoreLane(s, StoreLaneVec64x2)"),
+    ("i8x16.popcnt",         "makeUnary(s, UnaryOp::PopcntVecI8x16)"),
     ("i8x16.abs",            "makeUnary(s, UnaryOp::AbsVecI8x16)"),
     ("i8x16.neg",            "makeUnary(s, UnaryOp::NegVecI8x16)"),
     ("i8x16.any_true",       "makeUnary(s, UnaryOp::AnyTrueVecI8x16)"),
@@ -390,6 +404,11 @@
     ("i16x8.max_s",          "makeBinary(s, BinaryOp::MaxSVecI16x8)"),
     ("i16x8.max_u",          "makeBinary(s, BinaryOp::MaxUVecI16x8)"),
     ("i16x8.avgr_u",         "makeBinary(s, BinaryOp::AvgrUVecI16x8)"),
+    ("i16x8.q15mulr_sat_s",  "makeBinary(s, BinaryOp::Q15MulrSatSVecI16x8)"),
+    ("i16x8.extmul_low_i8x16_s", "makeBinary(s, BinaryOp::ExtMulLowSVecI16x8)"),
+    ("i16x8.extmul_high_i8x16_s", "makeBinary(s, BinaryOp::ExtMulHighSVecI16x8)"),
+    ("i16x8.extmul_low_i8x16_u", "makeBinary(s, BinaryOp::ExtMulLowUVecI16x8)"),
+    ("i16x8.extmul_high_i8x16_u", "makeBinary(s, BinaryOp::ExtMulHighUVecI16x8)"),
     ("i32x4.abs",            "makeUnary(s, UnaryOp::AbsVecI32x4)"),
     ("i32x4.neg",            "makeUnary(s, UnaryOp::NegVecI32x4)"),
     ("i32x4.any_true",       "makeUnary(s, UnaryOp::AnyTrueVecI32x4)"),
@@ -406,15 +425,22 @@
     ("i32x4.max_s",          "makeBinary(s, BinaryOp::MaxSVecI32x4)"),
     ("i32x4.max_u",          "makeBinary(s, BinaryOp::MaxUVecI32x4)"),
     ("i32x4.dot_i16x8_s",    "makeBinary(s, BinaryOp::DotSVecI16x8ToVecI32x4)"),
+    ("i32x4.extmul_low_i16x8_s", "makeBinary(s, BinaryOp::ExtMulLowSVecI32x4)"),
+    ("i32x4.extmul_high_i16x8_s", "makeBinary(s, BinaryOp::ExtMulHighSVecI32x4)"),
+    ("i32x4.extmul_low_i16x8_u", "makeBinary(s, BinaryOp::ExtMulLowUVecI32x4)"),
+    ("i32x4.extmul_high_i16x8_u", "makeBinary(s, BinaryOp::ExtMulHighUVecI32x4)"),
     ("i64x2.neg",            "makeUnary(s, UnaryOp::NegVecI64x2)"),
-    ("i64x2.any_true",       "makeUnary(s, UnaryOp::AnyTrueVecI64x2)"),
-    ("i64x2.all_true",       "makeUnary(s, UnaryOp::AllTrueVecI64x2)"),
+    ("i64x2.bitmask",        "makeUnary(s, UnaryOp::BitmaskVecI64x2)"),
     ("i64x2.shl",            "makeSIMDShift(s, SIMDShiftOp::ShlVecI64x2)"),
     ("i64x2.shr_s",          "makeSIMDShift(s, SIMDShiftOp::ShrSVecI64x2)"),
     ("i64x2.shr_u",          "makeSIMDShift(s, SIMDShiftOp::ShrUVecI64x2)"),
     ("i64x2.add",            "makeBinary(s, BinaryOp::AddVecI64x2)"),
     ("i64x2.sub",            "makeBinary(s, BinaryOp::SubVecI64x2)"),
     ("i64x2.mul",            "makeBinary(s, BinaryOp::MulVecI64x2)"),
+    ("i64x2.extmul_low_i32x4_s", "makeBinary(s, BinaryOp::ExtMulLowSVecI64x2)"),
+    ("i64x2.extmul_high_i32x4_s", "makeBinary(s, BinaryOp::ExtMulHighSVecI64x2)"),
+    ("i64x2.extmul_low_i32x4_u", "makeBinary(s, BinaryOp::ExtMulLowUVecI64x2)"),
+    ("i64x2.extmul_high_i32x4_u", "makeBinary(s, BinaryOp::ExtMulHighUVecI64x2)"),
     ("f32x4.abs",            "makeUnary(s, UnaryOp::AbsVecF32x4)"),
     ("f32x4.neg",            "makeUnary(s, UnaryOp::NegVecF32x4)"),
     ("f32x4.sqrt",           "makeUnary(s, UnaryOp::SqrtVecF32x4)"),
@@ -481,7 +507,18 @@
     ("i32x4.widen_high_i16x8_s", "makeUnary(s, UnaryOp::WidenHighSVecI16x8ToVecI32x4)"),
     ("i32x4.widen_low_i16x8_u",  "makeUnary(s, UnaryOp::WidenLowUVecI16x8ToVecI32x4)"),
     ("i32x4.widen_high_i16x8_u", "makeUnary(s, UnaryOp::WidenHighUVecI16x8ToVecI32x4)"),
+    ("i64x2.widen_low_i32x4_s",  "makeUnary(s, UnaryOp::WidenLowSVecI32x4ToVecI64x2)"),
+    ("i64x2.widen_high_i32x4_s", "makeUnary(s, UnaryOp::WidenHighSVecI32x4ToVecI64x2)"),
+    ("i64x2.widen_low_i32x4_u",  "makeUnary(s, UnaryOp::WidenLowUVecI32x4ToVecI64x2)"),
+    ("i64x2.widen_high_i32x4_u", "makeUnary(s, UnaryOp::WidenHighUVecI32x4ToVecI64x2)"),
     ("v8x16.swizzle",            "makeBinary(s, BinaryOp::SwizzleVec8x16)"),
+    ("i16x8.extadd_pairwise_i8x16_s", "makeUnary(s, UnaryOp::ExtAddPairwiseSVecI8x16ToI16x8)"),
+    ("i16x8.extadd_pairwise_i8x16_u", "makeUnary(s, UnaryOp::ExtAddPairwiseUVecI8x16ToI16x8)"),
+    ("i32x4.extadd_pairwise_i16x8_s", "makeUnary(s, UnaryOp::ExtAddPairwiseSVecI16x8ToI32x4)"),
+    ("i32x4.extadd_pairwise_i16x8_u", "makeUnary(s, UnaryOp::ExtAddPairwiseUVecI16x8ToI32x4)"),
+    # prefetch instructions
+    ("prefetch.t",  "makePrefetch(s, PrefetchOp::PrefetchTemporal)"),
+    ("prefetch.nt", "makePrefetch(s, PrefetchOp::PrefetchNontemporal)"),
     # reference types instructions
     # TODO Add table instructions
     ("ref.null",             "makeRefNull(s)"),
@@ -496,6 +533,9 @@
     ("tuple.make",           "makeTupleMake(s)"),
     ("tuple.extract",        "makeTupleExtract(s)"),
     ("pop",                  "makePop(s)"),
+    # Typed function references instructions
+    ("call_ref",             "makeCallRef(s, /*isReturn=*/false)"),
+    ("return_call_ref",      "makeCallRef(s, /*isReturn=*/true)"),
     # GC
     ("ref.eq",               "makeRefEq(s)"),
     ("i31.new",              "makeI31New(s)"),
diff --git a/binaryen/scripts/not.py b/binaryen/scripts/not.py
new file mode 100644
--- /dev/null
+++ b/binaryen/scripts/not.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+
+# 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.
+
+import sys
+import subprocess
+
+
+# Emulate the `not` tool from LLVM's test infrastructure for use with lit and
+# FileCheck. It succeeds if the given subcommand fails and vice versa.
+def main():
+    cmd = sys.argv[1:]
+    result = subprocess.run(cmd)
+    sys.exit(0 if result.returncode != 0 else 1)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/binaryen/scripts/process_optimize_instructions.py b/binaryen/scripts/process_optimize_instructions.py
deleted file mode 100644
--- a/binaryen/scripts/process_optimize_instructions.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/python
-
-import os
-
-root = os.path.dirname(os.path.dirname(__file__))
-
-infile = os.path.join(root, 'src', 'passes', 'OptimizeInstructions.wast')
-outfile = os.path.join(root, 'src', 'passes',
-                       'OptimizeInstructions.wast.processed')
-
-out = open(outfile, 'w')
-
-for line in open(infile):
-    out.write('"' + line.strip().replace('"', '\\"') + '\\n"\n')
-
-out.close()
diff --git a/binaryen/scripts/test/generate_lld_tests.py b/binaryen/scripts/test/generate_lld_tests.py
--- a/binaryen/scripts/test/generate_lld_tests.py
+++ b/binaryen/scripts/test/generate_lld_tests.py
@@ -48,10 +48,10 @@
         wasm_path = os.path.join(lld_path, wasm_file)
         wat_path = os.path.join(lld_path, wat_file)
         is_shared = 'shared' in src_file
+        is_64 = '64' in src_file
 
         compile_cmd = [
             os.path.join(llvm_bin, 'clang'), src_path, '-o', obj_path,
-            '--target=wasm32-emscripten',
             '-mllvm', '-enable-emscripten-sjlj',
             '-c',
             '-nostdinc',
@@ -67,7 +67,6 @@
             obj_path, '-o', wasm_path,
             '--allow-undefined',
             '--export', '__wasm_call_ctors',
-            '--export', '__data_end',
             '--global-base=568',
         ]
         # We had a regression where this test only worked if debug names
@@ -81,6 +80,12 @@
             link_cmd.append('--experimental-pic')
         else:
             link_cmd.append('--entry=main')
+
+        if is_64:
+            compile_cmd.append('--target=wasm64-emscripten')
+            link_cmd.append('-mwasm64')
+        else:
+            compile_cmd.append('--target=wasm32-emscripten')
 
         try:
             support.run_command(compile_cmd)
diff --git a/binaryen/scripts/test/lld.py b/binaryen/scripts/test/lld.py
--- a/binaryen/scripts/test/lld.py
+++ b/binaryen/scripts/test/lld.py
@@ -26,8 +26,6 @@
         ret += ['--side-module']
     if 'standalone-wasm' in filename:
         ret += ['--standalone-wasm']
-    if 'bigint' in filename:
-        ret += ['--bigint']
     return ret
 
 
@@ -51,7 +49,10 @@
             else:
                 continue
 
-        cmd = shared.WASM_EMSCRIPTEN_FINALIZE + [input_path, '-S'] + args
+        cmd = shared.WASM_EMSCRIPTEN_FINALIZE + args
+        if '64' in input_path:
+            cmd += ['--enable-memory64', '--bigint']
+        cmd += [input_path, '-S']
         cmd += args_for_finalize(os.path.basename(input_path))
         actual = support.run_command(cmd)
 
@@ -96,9 +97,12 @@
             out_path = input_path + ext
             if ext != '.out' and not os.path.exists(out_path):
                 continue
-            cmd = shared.WASM_EMSCRIPTEN_FINALIZE + [input_path, '-S'] + \
-                ext_args
+            cmd = shared.WASM_EMSCRIPTEN_FINALIZE + ext_args
+            if '64' in input_path:
+                cmd += ['--enable-memory64', '--bigint']
+            cmd += [input_path, '-S']
             cmd += args_for_finalize(os.path.basename(input_path))
             actual = support.run_command(cmd)
+
             with open(out_path, 'w') as o:
                 o.write(actual)
diff --git a/binaryen/scripts/test/shared.py b/binaryen/scripts/test/shared.py
--- a/binaryen/scripts/test/shared.py
+++ b/binaryen/scripts/test/shared.py
@@ -49,15 +49,17 @@
         help=('If set, the whole test suite will run to completion independent of'
               ' earlier errors.'))
     parser.add_argument(
-        '--interpreter', dest='interpreter', default='',
-        help='Specifies the wasm interpreter executable to run tests on.')
-    parser.add_argument(
         '--binaryen-bin', dest='binaryen_bin', default='',
-        help=('Specifies a path to where the built Binaryen executables reside at.'
-              ' Default: bin/ of current directory (i.e. assume an in-tree build).'
+        help=('Specifies the path to the Binaryen executables in the CMake build'
+              ' directory. Default: bin/ of current directory (i.e. assume an'
+              ' in-tree build).'
               ' If not specified, the environment variable BINARYEN_ROOT= can also'
               ' be used to adjust this.'))
     parser.add_argument(
+        '--binaryen-lib', dest='binaryen_lib', default='',
+        help=('Specifies a path to where the built Binaryen shared library resides at.'
+              ' Default: ./lib relative to bin specified above.'))
+    parser.add_argument(
         '--binaryen-root', dest='binaryen_root', default='',
         help=('Specifies a path to the root of the Binaryen repository tree.'
               ' Default: the directory where this file check.py resides.'))
@@ -123,10 +125,17 @@
 
 options.binaryen_bin = os.path.normpath(os.path.abspath(options.binaryen_bin))
 
+if not options.binaryen_lib:
+    options.binaryen_lib = os.path.join(os.path.dirname(options.binaryen_bin),  'lib')
+
+options.binaryen_lib = os.path.normpath(os.path.abspath(options.binaryen_lib))
+
+options.binaryen_build = os.path.dirname(options.binaryen_bin)
+
 # ensure BINARYEN_ROOT is set up
 os.environ['BINARYEN_ROOT'] = os.path.dirname(options.binaryen_bin)
 
-wasm_dis_filenames = ['wasm-dis', 'wasm-dis.exe']
+wasm_dis_filenames = ['wasm-dis', 'wasm-dis.exe', 'wasm-dis.js']
 if not any(os.path.isfile(os.path.join(options.binaryen_bin, f))
            for f in wasm_dis_filenames):
     warn('Binaryen not found (or has not been successfully built to bin/ ?')
@@ -182,7 +191,7 @@
             which('gcc') or which('clang'))
 NATIVEXX = (os.environ.get('CXX') or which('mingw32-g++') or
             which('g++') or which('clang++'))
-NODEJS = os.getenv('NODE', which('nodejs') or which('node'))
+NODEJS = os.getenv('NODE', which('node') or which('nodejs'))
 MOZJS = which('mozjs') or which('spidermonkey')
 V8 = which('v8') or which('d8')
 
@@ -261,18 +270,7 @@
 if NODEJS is None:
     warn('no node found (did not check proper js form)')
 
-try:
-    if MOZJS is not None:
-        subprocess.check_call([MOZJS, '--version'],
-                              stdout=subprocess.PIPE,
-                              stderr=subprocess.PIPE)
-except (OSError, subprocess.CalledProcessError):
-    MOZJS = None
-if MOZJS is None:
-    warn('no mozjs found (did not check native wasm support nor asm.js'
-         ' validation)')
 
-
 # utilities
 
 # removes a file if it exists, using any and all ways of doing so
@@ -380,10 +378,6 @@
     if options.test_name_filter:
         tests = fnmatch.filter(tests, options.test_name_filter)
     return sorted(tests)
-
-
-if not options.interpreter:
-    warn('no interpreter provided (did not test spec interpreter validation)')
 
 
 if not options.spec_tests:
diff --git a/binaryen/scripts/test/wasm_opt.py b/binaryen/scripts/test/wasm_opt.py
--- a/binaryen/scripts/test/wasm_opt.py
+++ b/binaryen/scripts/test/wasm_opt.py
@@ -57,7 +57,8 @@
         passes_file = os.path.join(shared.get_test_dir('passes'), passname + '.passes')
         if os.path.exists(passes_file):
             passname = open(passes_file).read().strip()
-        opts = [('--' + p if not p.startswith('O') and p != 'g' else '-' + p) for p in passname.split('_')]
+        passes = [p for p in passname.split('_') if p != 'noprint']
+        opts = [('--' + p if not p.startswith('O') and p != 'g' else '-' + p) for p in passes]
         actual = ''
         for module, asserts in support.split_wast(t):
             assert len(asserts) == 0
@@ -171,7 +172,8 @@
         passes_file = os.path.join(shared.get_test_dir('passes'), passname + '.passes')
         if os.path.exists(passes_file):
             passname = open(passes_file).read().strip()
-        opts = [('--' + p if not p.startswith('O') and p != 'g' else '-' + p) for p in passname.split('_')]
+        passes = [p for p in passname.split('_') if p != 'noprint']
+        opts = [('--' + p if not p.startswith('O') and p != 'g' else '-' + p) for p in passes]
         actual = ''
         for module, asserts in support.split_wast(t):
             assert len(asserts) == 0
diff --git a/binaryen/src/abi/abi.h b/binaryen/src/abi/abi.h
deleted file mode 100644
--- a/binaryen/src/abi/abi.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef wasm_abi_abi_h
-#define wasm_abi_abi_h
-
-#include "wasm.h"
-
-namespace wasm {
-
-namespace ABI {
-
-// The pointer type. Will need to update this for wasm64
-const static Type PointerType = Type::i32;
-
-} // namespace ABI
-
-} // namespace wasm
-
-#endif // wasm_abi_abi_h
diff --git a/binaryen/src/abi/stack.h b/binaryen/src/abi/stack.h
deleted file mode 100644
--- a/binaryen/src/abi/stack.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef wasm_abi_stack_h
-#define wasm_abi_stack_h
-
-#include "abi.h"
-#include "asmjs/shared-constants.h"
-#include "ir/find_all.h"
-#include "ir/global-utils.h"
-#include "shared-constants.h"
-#include "wasm-builder.h"
-#include "wasm.h"
-
-namespace wasm {
-
-namespace ABI {
-
-enum { StackAlign = 16 };
-
-inline Index stackAlign(Index size) {
-  return (size + StackAlign - 1) & -StackAlign;
-}
-
-// Allocate some space on the stack, and assign it to a local.
-// The local will have the same constant value in all the function, so you can
-// just local.get it anywhere there.
-//
-// FIXME: This function assumes that the stack grows upward, per the convention
-// used by fastcomp.  The stack grows downward when using the WASM backend.
-
-inline void
-getStackSpace(Index local, Function* func, Index size, Module& wasm) {
-  // Attempt to locate the stack pointer by recognizing code idioms
-  // used by Emscripten.  First, look for a global initialized to an
-  // imported variable named "STACKTOP" in environment "env".
-  auto* stackPointer =
-    GlobalUtils::getGlobalInitializedToImport(wasm, ENV, "STACKTOP");
-  // Starting with Emscripten 1.38.24, the stack pointer variable is
-  // initialized with a literal constant, eliminating the import that
-  // we used to locate the stack pointer by name.  We must match a more
-  // complicated idiom, expecting to see the module structured as follows:
-  //
-  //(module
-  //  ...
-  //  (export "stackSave" (func $stackSave))
-  //  ...
-  //  (func $stackSave (; 410 ;) (; has Stack IR ;) (result i32)
-  //    (global.get $STACKTOP)
-  //  )
-  //  ...
-  //)
-  if (!stackPointer) {
-    auto* stackSaveFunctionExport = wasm.getExportOrNull("stackSave");
-    if (stackSaveFunctionExport &&
-        stackSaveFunctionExport->kind == ExternalKind::Function) {
-      auto* stackSaveFunction =
-        wasm.getFunction(stackSaveFunctionExport->value);
-      assert(!stackSaveFunction->imported());
-      auto* globalGet = stackSaveFunction->body->dynCast<GlobalGet>();
-      if (globalGet) {
-        stackPointer = wasm.getGlobal(globalGet->name);
-      }
-    }
-  }
-  if (!stackPointer) {
-    Fatal() << "getStackSpace: failed to find the stack pointer";
-  }
-  // align the size
-  size = stackAlign(size);
-  // TODO: find existing stack usage, and add on top of that - carefully
-  Builder builder(wasm);
-  auto* block = builder.makeBlock();
-  block->list.push_back(builder.makeLocalSet(
-    local, builder.makeGlobalGet(stackPointer->name, PointerType)));
-  // TODO: add stack max check
-  Expression* added;
-  if (PointerType == Type::i32) {
-    added = builder.makeBinary(AddInt32,
-                               builder.makeLocalGet(local, PointerType),
-                               builder.makeConst(int32_t(size)));
-  } else {
-    WASM_UNREACHABLE("unhandled PointerType");
-  }
-  block->list.push_back(builder.makeGlobalSet(stackPointer->name, added));
-  auto makeStackRestore = [&]() {
-    return builder.makeGlobalSet(stackPointer->name,
-                                 builder.makeLocalGet(local, PointerType));
-  };
-  // add stack restores to the returns
-  FindAllPointers<Return> finder(func->body);
-  for (auto** ptr : finder.list) {
-    auto* ret = (*ptr)->cast<Return>();
-    if (ret->value && ret->value->type != Type::unreachable) {
-      // handle the returned value
-      auto* block = builder.makeBlock();
-      auto temp = builder.addVar(func, ret->value->type);
-      block->list.push_back(builder.makeLocalSet(temp, ret->value));
-      block->list.push_back(makeStackRestore());
-      block->list.push_back(
-        builder.makeReturn(builder.makeLocalGet(temp, ret->value->type)));
-      block->finalize();
-      *ptr = block;
-    } else {
-      // restore, then return
-      *ptr = builder.makeSequence(makeStackRestore(), ret);
-    }
-  }
-  // add stack restores to the body
-  if (func->body->type == Type::none) {
-    block->list.push_back(func->body);
-    block->list.push_back(makeStackRestore());
-  } else if (func->body->type == Type::unreachable) {
-    block->list.push_back(func->body);
-    // no need to restore the old stack value, we're gone anyhow
-  } else {
-    // save the return value
-    auto temp = builder.addVar(func, func->sig.results);
-    block->list.push_back(builder.makeLocalSet(temp, func->body));
-    block->list.push_back(makeStackRestore());
-    block->list.push_back(builder.makeLocalGet(temp, func->sig.results));
-  }
-  block->finalize();
-  func->body = block;
-}
-
-} // namespace ABI
-
-} // namespace wasm
-
-#endif // wasm_abi_stack_h
diff --git a/binaryen/src/abi/wasm-object.h b/binaryen/src/abi/wasm-object.h
deleted file mode 100644
--- a/binaryen/src/abi/wasm-object.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-//
-// Contains definitions used for wasm object files.
-// See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
-//
-
-#ifndef wasm_abi_wasm_object_h
-#define wasm_abi_wasm_object_h
-
-namespace wasm {
-
-namespace ABI {
-enum LinkType : unsigned {
-  WASM_STACK_POINTER = 0x1,
-  WASM_SYMBOL_INFO = 0x2,
-  WASM_DATA_SIZE = 0x3,
-  WASM_DATA_ALIGNMENT = 0x4,
-  WASM_SEGMENT_INFO = 0x5,
-  WASM_INIT_FUNCS = 0x6,
-};
-} // namespace ABI
-
-} // namespace wasm
-
-#endif // wasm_abi_wasm_object_h
diff --git a/binaryen/src/asm_v_wasm.h b/binaryen/src/asm_v_wasm.h
--- a/binaryen/src/asm_v_wasm.h
+++ b/binaryen/src/asm_v_wasm.h
@@ -23,26 +23,12 @@
 
 namespace wasm {
 
-Type asmToWasmType(AsmType asmType);
-
 AsmType wasmToAsmType(Type type);
 
 char getSig(Type type);
 std::string getSig(Function* func);
 std::string getSig(Type results, Type params);
 
-template<typename T,
-         typename std::enable_if<std::is_base_of<Expression, T>::value>::type* =
-           nullptr>
-std::string getSig(T* call) {
-  std::string ret;
-  ret += getSig(call->type);
-  for (auto operand : call->operands) {
-    ret += getSig(operand->type);
-  }
-  return ret;
-}
-
 template<typename ListType>
 std::string getSig(Type result, const ListType& operands) {
   std::string ret;
@@ -62,9 +48,6 @@
   }
   return ret;
 }
-
-// converts an f32 to an f64 if necessary
-Expression* ensureDouble(Expression* expr, MixedArena& allocator);
 
 } // namespace wasm
 
diff --git a/binaryen/src/asmjs/asm_v_wasm.cpp b/binaryen/src/asmjs/asm_v_wasm.cpp
--- a/binaryen/src/asmjs/asm_v_wasm.cpp
+++ b/binaryen/src/asmjs/asm_v_wasm.cpp
@@ -19,28 +19,6 @@
 
 namespace wasm {
 
-Type asmToWasmType(AsmType asmType) {
-  switch (asmType) {
-    case ASM_INT:
-      return Type::i32;
-    case ASM_DOUBLE:
-      return Type::f64;
-    case ASM_FLOAT:
-      return Type::f32;
-    case ASM_INT64:
-      return Type::i64;
-    case ASM_NONE:
-      return Type::none;
-    case ASM_FLOAT32X4:
-    case ASM_FLOAT64X2:
-    case ASM_INT8X16:
-    case ASM_INT16X8:
-    case ASM_INT32X4:
-      return Type::v128;
-  }
-  WASM_UNREACHABLE("invalid type");
-}
-
 AsmType wasmToAsmType(Type type) {
   TODO_SINGLE_COMPOUND(type);
   switch (type.getBasic()) {
@@ -102,10 +80,6 @@
   WASM_UNREACHABLE("invalid type");
 }
 
-std::string getSig(Function* func) {
-  return getSig(func->sig.results, func->sig.params);
-}
-
 std::string getSig(Type results, Type params) {
   assert(!results.isTuple());
   std::string sig;
@@ -114,18 +88,6 @@
     sig += getSig(param);
   }
   return sig;
-}
-
-Expression* ensureDouble(Expression* expr, MixedArena& allocator) {
-  if (expr->type == Type::f32) {
-    auto conv = allocator.alloc<Unary>();
-    conv->op = PromoteFloat32;
-    conv->value = expr;
-    conv->type = Type::f64;
-    return conv;
-  }
-  assert(expr->type == Type::f64);
-  return expr;
 }
 
 } // namespace wasm
diff --git a/binaryen/src/asmjs/shared-constants.cpp b/binaryen/src/asmjs/shared-constants.cpp
--- a/binaryen/src/asmjs/shared-constants.cpp
+++ b/binaryen/src/asmjs/shared-constants.cpp
@@ -18,11 +18,6 @@
 
 namespace wasm {
 
-cashew::IString GLOBAL("global");
-cashew::IString NAN_("NaN");
-cashew::IString INFINITY_("Infinity");
-cashew::IString NAN__("nan");
-cashew::IString INFINITY__("infinity");
 cashew::IString TOPMOST("topmost");
 cashew::IString INT8ARRAY("Int8Array");
 cashew::IString INT16ARRAY("Int16Array");
@@ -34,7 +29,6 @@
 cashew::IString FLOAT64ARRAY("Float64Array");
 cashew::IString ARRAY_BUFFER("ArrayBuffer");
 cashew::IString ASM_MODULE("asmModule");
-cashew::IString IMPOSSIBLE_CONTINUE("impossible-continue");
 cashew::IString MATH("Math");
 cashew::IString IMUL("imul");
 cashew::IString CLZ32("clz32");
@@ -55,10 +49,10 @@
 cashew::IString I32U_DIV("i32u-div");
 cashew::IString I32S_REM("i32s-rem");
 cashew::IString I32U_REM("i32u-rem");
-cashew::IString GLOBAL_MATH("global.Math");
 cashew::IString ABS("abs");
 cashew::IString FLOOR("floor");
 cashew::IString CEIL("ceil");
+cashew::IString TRUNC("trunc");
 cashew::IString SQRT("sqrt");
 cashew::IString POW("pow");
 cashew::IString I32_TEMP("asm2wasm_i32_temp");
@@ -93,8 +87,6 @@
 cashew::IString INT64_TO_32_HIGH_BITS("i64toi32_i32$HIGH_BITS");
 cashew::IString WASM_NEAREST_F32("__wasm_nearest_f32");
 cashew::IString WASM_NEAREST_F64("__wasm_nearest_f64");
-cashew::IString WASM_TRUNC_F32("__wasm_trunc_f32");
-cashew::IString WASM_TRUNC_F64("__wasm_trunc_f64");
 cashew::IString WASM_I64_MUL("__wasm_i64_mul");
 cashew::IString WASM_I64_SDIV("__wasm_i64_sdiv");
 cashew::IString WASM_I64_UDIV("__wasm_i64_udiv");
diff --git a/binaryen/src/asmjs/shared-constants.h b/binaryen/src/asmjs/shared-constants.h
--- a/binaryen/src/asmjs/shared-constants.h
+++ b/binaryen/src/asmjs/shared-constants.h
@@ -21,11 +21,6 @@
 
 namespace wasm {
 
-extern cashew::IString GLOBAL;
-extern cashew::IString NAN_;
-extern cashew::IString INFINITY_;
-extern cashew::IString NAN__;
-extern cashew::IString INFINITY__;
 extern cashew::IString TOPMOST;
 extern cashew::IString INT8ARRAY;
 extern cashew::IString INT16ARRAY;
@@ -37,7 +32,6 @@
 extern cashew::IString FLOAT64ARRAY;
 extern cashew::IString ARRAY_BUFFER;
 extern cashew::IString ASM_MODULE;
-extern cashew::IString IMPOSSIBLE_CONTINUE;
 extern cashew::IString MATH;
 extern cashew::IString IMUL;
 extern cashew::IString CLZ32;
@@ -58,10 +52,10 @@
 extern cashew::IString I32U_DIV;
 extern cashew::IString I32S_REM;
 extern cashew::IString I32U_REM;
-extern cashew::IString GLOBAL_MATH;
 extern cashew::IString ABS;
 extern cashew::IString FLOOR;
 extern cashew::IString CEIL;
+extern cashew::IString TRUNC;
 extern cashew::IString SQRT;
 extern cashew::IString POW;
 extern cashew::IString I32_TEMP;
@@ -73,8 +67,8 @@
 extern cashew::IString INSTRUMENT;
 extern cashew::IString MATH_IMUL;
 extern cashew::IString MATH_ABS;
-extern cashew::IString MATH_CEIL;
 extern cashew::IString MATH_CLZ32;
+extern cashew::IString MATH_CEIL;
 extern cashew::IString MATH_FLOOR;
 extern cashew::IString MATH_TRUNC;
 extern cashew::IString MATH_SQRT;
@@ -96,8 +90,6 @@
 extern cashew::IString INT64_TO_32_HIGH_BITS;
 extern cashew::IString WASM_NEAREST_F32;
 extern cashew::IString WASM_NEAREST_F64;
-extern cashew::IString WASM_TRUNC_F32;
-extern cashew::IString WASM_TRUNC_F64;
 extern cashew::IString WASM_I64_MUL;
 extern cashew::IString WASM_I64_SDIV;
 extern cashew::IString WASM_I64_UDIV;
diff --git a/binaryen/src/binaryen-c.cpp b/binaryen/src/binaryen-c.cpp
--- a/binaryen/src/binaryen-c.cpp
+++ b/binaryen/src/binaryen-c.cpp
@@ -29,7 +29,6 @@
 #include "wasm-binary.h"
 #include "wasm-builder.h"
 #include "wasm-interpreter.h"
-#include "wasm-printing.h"
 #include "wasm-s-parser.h"
 #include "wasm-validator.h"
 #include "wasm.h"
@@ -178,152 +177,14 @@
 BinaryenExpressionId BinaryenInvalidId(void) {
   return Expression::Id::InvalidId;
 }
-BinaryenExpressionId BinaryenBlockId(void) { return Expression::Id::BlockId; }
-BinaryenExpressionId BinaryenIfId(void) { return Expression::Id::IfId; }
-BinaryenExpressionId BinaryenLoopId(void) { return Expression::Id::LoopId; }
-BinaryenExpressionId BinaryenBreakId(void) { return Expression::Id::BreakId; }
-BinaryenExpressionId BinaryenSwitchId(void) { return Expression::Id::SwitchId; }
-BinaryenExpressionId BinaryenCallId(void) { return Expression::Id::CallId; }
-BinaryenExpressionId BinaryenCallIndirectId(void) {
-  return Expression::Id::CallIndirectId;
-}
-BinaryenExpressionId BinaryenLocalGetId(void) {
-  return Expression::Id::LocalGetId;
-}
-BinaryenExpressionId BinaryenLocalSetId(void) {
-  return Expression::Id::LocalSetId;
-}
-BinaryenExpressionId BinaryenGlobalGetId(void) {
-  return Expression::Id::GlobalGetId;
-}
-BinaryenExpressionId BinaryenGlobalSetId(void) {
-  return Expression::Id::GlobalSetId;
-}
-BinaryenExpressionId BinaryenLoadId(void) { return Expression::Id::LoadId; }
-BinaryenExpressionId BinaryenStoreId(void) { return Expression::Id::StoreId; }
-BinaryenExpressionId BinaryenConstId(void) { return Expression::Id::ConstId; }
-BinaryenExpressionId BinaryenUnaryId(void) { return Expression::Id::UnaryId; }
-BinaryenExpressionId BinaryenBinaryId(void) { return Expression::Id::BinaryId; }
-BinaryenExpressionId BinaryenSelectId(void) { return Expression::Id::SelectId; }
-BinaryenExpressionId BinaryenDropId(void) { return Expression::Id::DropId; }
-BinaryenExpressionId BinaryenReturnId(void) { return Expression::Id::ReturnId; }
-BinaryenExpressionId BinaryenMemorySizeId(void) {
-  return Expression::Id::MemorySizeId;
-}
-BinaryenExpressionId BinaryenMemoryGrowId(void) {
-  return Expression::Id::MemoryGrowId;
-}
-BinaryenExpressionId BinaryenNopId(void) { return Expression::Id::NopId; }
-BinaryenExpressionId BinaryenUnreachableId(void) {
-  return Expression::Id::UnreachableId;
-}
-BinaryenExpressionId BinaryenAtomicCmpxchgId(void) {
-  return Expression::Id::AtomicCmpxchgId;
-}
-BinaryenExpressionId BinaryenAtomicRMWId(void) {
-  return Expression::Id::AtomicRMWId;
-}
-BinaryenExpressionId BinaryenAtomicWaitId(void) {
-  return Expression::Id::AtomicWaitId;
-}
-BinaryenExpressionId BinaryenAtomicNotifyId(void) {
-  return Expression::Id::AtomicNotifyId;
-}
-BinaryenExpressionId BinaryenAtomicFenceId(void) {
-  return Expression::Id::AtomicFenceId;
-}
-BinaryenExpressionId BinaryenSIMDExtractId(void) {
-  return Expression::Id::SIMDExtractId;
-}
-BinaryenExpressionId BinaryenSIMDReplaceId(void) {
-  return Expression::Id::SIMDReplaceId;
-}
-BinaryenExpressionId BinaryenSIMDShuffleId(void) {
-  return Expression::Id::SIMDShuffleId;
-}
-BinaryenExpressionId BinaryenSIMDTernaryId(void) {
-  return Expression::Id::SIMDTernaryId;
-}
-BinaryenExpressionId BinaryenSIMDShiftId(void) {
-  return Expression::Id::SIMDShiftId;
-}
-BinaryenExpressionId BinaryenSIMDLoadId(void) {
-  return Expression::Id::SIMDLoadId;
-}
-BinaryenExpressionId BinaryenMemoryInitId(void) {
-  return Expression::Id::MemoryInitId;
-}
-BinaryenExpressionId BinaryenDataDropId(void) {
-  return Expression::Id::DataDropId;
-}
-BinaryenExpressionId BinaryenMemoryCopyId(void) {
-  return Expression::Id::MemoryCopyId;
-}
-BinaryenExpressionId BinaryenMemoryFillId(void) {
-  return Expression::Id::MemoryFillId;
-}
-BinaryenExpressionId BinaryenRefNullId(void) {
-  return Expression::Id::RefNullId;
-}
-BinaryenExpressionId BinaryenRefIsNullId(void) {
-  return Expression::Id::RefIsNullId;
-}
-BinaryenExpressionId BinaryenRefFuncId(void) {
-  return Expression::Id::RefFuncId;
-}
-BinaryenExpressionId BinaryenRefEqId(void) { return Expression::Id::RefEqId; }
-BinaryenExpressionId BinaryenTryId(void) { return Expression::Id::TryId; }
-BinaryenExpressionId BinaryenThrowId(void) { return Expression::Id::ThrowId; }
-BinaryenExpressionId BinaryenRethrowId(void) {
-  return Expression::Id::RethrowId;
-}
-BinaryenExpressionId BinaryenBrOnExnId(void) {
-  return Expression::Id::BrOnExnId;
-}
-BinaryenExpressionId BinaryenTupleMakeId(void) {
-  return Expression::Id::TupleMakeId;
-}
-BinaryenExpressionId BinaryenTupleExtractId(void) {
-  return Expression::Id::TupleExtractId;
-}
-BinaryenExpressionId BinaryenPopId(void) { return Expression::Id::PopId; }
-BinaryenExpressionId BinaryenI31NewId(void) { return Expression::Id::I31NewId; }
-BinaryenExpressionId BinaryenI31GetId(void) { return Expression::Id::I31GetId; }
-BinaryenExpressionId BinaryenRefTestId(void) {
-  return Expression::Id::RefTestId;
-}
-BinaryenExpressionId BinaryenRefCastId(void) {
-  return Expression::Id::RefCastId;
-}
-BinaryenExpressionId BinaryenBrOnCastId(void) {
-  return Expression::Id::BrOnCastId;
-}
-BinaryenExpressionId BinaryenRttCanonId(void) {
-  return Expression::Id::RttCanonId;
-}
-BinaryenExpressionId BinaryenRttSubId(void) { return Expression::Id::RttSubId; }
-BinaryenExpressionId BinaryenStructNewId(void) {
-  return Expression::Id::StructNewId;
-}
-BinaryenExpressionId BinaryenStructGetId(void) {
-  return Expression::Id::StructGetId;
-}
-BinaryenExpressionId BinaryenStructSetId(void) {
-  return Expression::Id::StructSetId;
-}
-BinaryenExpressionId BinaryenArrayNewId(void) {
-  return Expression::Id::ArrayNewId;
-}
-BinaryenExpressionId BinaryenArrayGetId(void) {
-  return Expression::Id::ArrayGetId;
-}
-BinaryenExpressionId BinaryenArraySetId(void) {
-  return Expression::Id::ArraySetId;
-}
-BinaryenExpressionId BinaryenArrayLenId(void) {
-  return Expression::Id::ArrayLenId;
-}
 
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  BinaryenExpressionId Binaryen##CLASS_TO_VISIT##Id(void) {                    \
+    return Expression::Id::CLASS_TO_VISIT##Id;                                 \
+  }
+
+#include "wasm-delegations.h"
+
 // External kinds
 
 BinaryenExternalKind BinaryenExternalFunction(void) {
@@ -562,12 +423,12 @@
 BinaryenOp BinaryenLeFloat64(void) { return LeFloat64; }
 BinaryenOp BinaryenGtFloat64(void) { return GtFloat64; }
 BinaryenOp BinaryenGeFloat64(void) { return GeFloat64; }
-BinaryenOp BinaryenAtomicRMWAdd(void) { return AtomicRMWOp::Add; }
-BinaryenOp BinaryenAtomicRMWSub(void) { return AtomicRMWOp::Sub; }
-BinaryenOp BinaryenAtomicRMWAnd(void) { return AtomicRMWOp::And; }
-BinaryenOp BinaryenAtomicRMWOr(void) { return AtomicRMWOp::Or; }
-BinaryenOp BinaryenAtomicRMWXor(void) { return AtomicRMWOp::Xor; }
-BinaryenOp BinaryenAtomicRMWXchg(void) { return AtomicRMWOp::Xchg; }
+BinaryenOp BinaryenAtomicRMWAdd(void) { return RMWAdd; }
+BinaryenOp BinaryenAtomicRMWSub(void) { return RMWSub; }
+BinaryenOp BinaryenAtomicRMWAnd(void) { return RMWAnd; }
+BinaryenOp BinaryenAtomicRMWOr(void) { return RMWOr; }
+BinaryenOp BinaryenAtomicRMWXor(void) { return RMWXor; }
+BinaryenOp BinaryenAtomicRMWXchg(void) { return RMWXchg; }
 BinaryenOp BinaryenTruncSatSFloat32ToInt32(void) {
   return TruncSatSFloat32ToInt32;
 }
@@ -719,8 +580,6 @@
   return DotSVecI16x8ToVecI32x4;
 }
 BinaryenOp BinaryenNegVecI64x2(void) { return NegVecI64x2; }
-BinaryenOp BinaryenAnyTrueVecI64x2(void) { return AnyTrueVecI64x2; }
-BinaryenOp BinaryenAllTrueVecI64x2(void) { return AllTrueVecI64x2; }
 BinaryenOp BinaryenShlVecI64x2(void) { return ShlVecI64x2; }
 BinaryenOp BinaryenShrSVecI64x2(void) { return ShrSVecI64x2; }
 BinaryenOp BinaryenShrUVecI64x2(void) { return ShrUVecI64x2; }
@@ -1325,9 +1184,11 @@
     Builder(*(Module*)module).makeRefIsNull((Expression*)value));
 }
 
-BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
-                                      const char* func) {
-  return static_cast<Expression*>(Builder(*(Module*)module).makeRefFunc(func));
+BinaryenExpressionRef
+BinaryenRefFunc(BinaryenModuleRef module, const char* func, BinaryenType type) {
+  Type type_(type);
+  return static_cast<Expression*>(
+    Builder(*(Module*)module).makeRefFunc(func, type_));
 }
 
 BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module,
@@ -1412,8 +1273,7 @@
   ((Expression*)expr)->type = Type(type);
 }
 void BinaryenExpressionPrint(BinaryenExpressionRef expr) {
-  WasmPrinter::printExpression((Expression*)expr, std::cout);
-  std::cout << '\n';
+  std::cout << *(Expression*)expr << '\n';
 }
 void BinaryenExpressionFinalize(BinaryenExpressionRef expr) {
   ReFinalizeNode().visit((Expression*)expr);
@@ -3131,7 +2991,7 @@
                                         BinaryenIndex numVarTypes,
                                         BinaryenExpressionRef body) {
   auto* ret = new Function;
-  ret->name = name;
+  ret->setExplicitName(name);
   ret->sig = Signature(Type(params), Type(results));
   for (BinaryenIndex i = 0; i < numVarTypes; i++) {
     ret->vars.push_back(Type(varTypes[i]));
@@ -3149,21 +3009,21 @@
 }
 BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module,
                                         const char* name) {
-  return ((Module*)module)->getFunction(name);
+  return ((Module*)module)->getFunctionOrNull(name);
 }
 void BinaryenRemoveFunction(BinaryenModuleRef module, const char* name) {
   ((Module*)module)->removeFunction(name);
 }
-uint32_t BinaryenGetNumFunctions(BinaryenModuleRef module) {
+BinaryenIndex BinaryenGetNumFunctions(BinaryenModuleRef module) {
   return ((Module*)module)->functions.size();
 }
 BinaryenFunctionRef BinaryenGetFunctionByIndex(BinaryenModuleRef module,
-                                               BinaryenIndex id) {
+                                               BinaryenIndex index) {
   const auto& functions = ((Module*)module)->functions;
-  if (functions.size() <= id) {
-    Fatal() << "invalid function id.";
+  if (functions.size() <= index) {
+    Fatal() << "invalid function index.";
   }
-  return functions[id].get();
+  return functions[index].get();
 }
 
 // Globals
@@ -3174,7 +3034,7 @@
                                     int8_t mutable_,
                                     BinaryenExpressionRef init) {
   auto* ret = new Global();
-  ret->name = name;
+  ret->setExplicitName(name);
   ret->type = Type(type);
   ret->mutable_ = !!mutable_;
   ret->init = (Expression*)init;
@@ -3183,11 +3043,22 @@
 }
 BinaryenGlobalRef BinaryenGetGlobal(BinaryenModuleRef module,
                                     const char* name) {
-  return ((Module*)module)->getGlobal(name);
+  return ((Module*)module)->getGlobalOrNull(name);
 }
 void BinaryenRemoveGlobal(BinaryenModuleRef module, const char* name) {
   ((Module*)module)->removeGlobal(name);
 }
+BinaryenIndex BinaryenGetNumGlobals(BinaryenModuleRef module) {
+  return ((Module*)module)->globals.size();
+}
+BinaryenGlobalRef BinaryenGetGlobalByIndex(BinaryenModuleRef module,
+                                           BinaryenIndex index) {
+  const auto& globals = ((Module*)module)->globals;
+  if (globals.size() <= index) {
+    Fatal() << "invalid global index.";
+  }
+  return globals[index].get();
+}
 
 // Events
 
@@ -3197,7 +3068,7 @@
                                   BinaryenType params,
                                   BinaryenType results) {
   auto* ret = new Event();
-  ret->name = name;
+  ret->setExplicitName(name);
   ret->attribute = attribute;
   ret->sig = Signature(Type(params), Type(results));
   ((Module*)module)->addEvent(ret);
@@ -3205,7 +3076,7 @@
 }
 
 BinaryenEventRef BinaryenGetEvent(BinaryenModuleRef module, const char* name) {
-  return ((Module*)module)->getEvent(name);
+  return ((Module*)module)->getEventOrNull(name);
 }
 void BinaryenRemoveEvent(BinaryenModuleRef module, const char* name) {
   ((Module*)module)->removeEvent(name);
@@ -3330,9 +3201,24 @@
   ((Module*)module)->addExport(ret);
   return ret;
 }
+BinaryenExportRef BinaryenGetExport(BinaryenModuleRef module,
+                                    const char* externalName) {
+  return ((Module*)module)->getExportOrNull(externalName);
+}
 void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName) {
   ((Module*)module)->removeExport(externalName);
 }
+BinaryenIndex BinaryenGetNumExports(BinaryenModuleRef module) {
+  return ((Module*)module)->exports.size();
+}
+BinaryenExportRef BinaryenGetExportByIndex(BinaryenModuleRef module,
+                                           BinaryenIndex index) {
+  const auto& exports = ((Module*)module)->exports;
+  if (exports.size() <= index) {
+    Fatal() << "invalid export index.";
+  }
+  return exports[index].get();
+}
 
 // Function table. One per module
 
@@ -3412,7 +3298,8 @@
     wasm->addExport(memoryExport.release());
   }
   for (BinaryenIndex i = 0; i < numSegments; i++) {
-    wasm->memory.segments.emplace_back(segmentPassive[i],
+    wasm->memory.segments.emplace_back(Name(),
+                                       segmentPassive[i],
                                        (Expression*)segmentOffsets[i],
                                        segments[i],
                                        segmentSizes[i]);
@@ -3518,7 +3405,7 @@
 }
 
 void BinaryenModulePrint(BinaryenModuleRef module) {
-  WasmPrinter::printModule((Module*)module);
+  std::cout << *(Module*)module;
 }
 
 void BinaryenModulePrintAsmjs(BinaryenModuleRef module) {
@@ -3682,7 +3569,7 @@
   // use a stringstream as an std::ostream. Extract the std::string
   // representation, and then store in the output.
   std::stringstream ss;
-  WasmPrinter::printModule((Module*)module, ss);
+  ss << *(Module*)module;
 
   const auto temp = ss.str();
   const auto ctemp = temp.c_str();
@@ -3727,7 +3614,7 @@
 
 char* BinaryenModuleAllocateAndWriteText(BinaryenModuleRef module) {
   std::stringstream ss;
-  WasmPrinter::printModule((Module*)module, ss);
+  ss << *(Module*)module;
 
   const std::string out = ss.str();
   const int len = out.length() + 1;
@@ -3822,7 +3709,7 @@
                               BinaryenModuleRef module) {
   PassRunner passRunner((Module*)module);
   passRunner.options = globalPassOptions;
-  passRunner.addDefaultOptimizationPasses();
+  passRunner.addDefaultFunctionOptimizationPasses();
   passRunner.runOnFunction((Function*)func);
 }
 void BinaryenFunctionRunPasses(BinaryenFunctionRef func,
@@ -3948,17 +3835,6 @@
 }
 const char* BinaryenExportGetValue(BinaryenExportRef export_) {
   return ((Export*)export_)->value.c_str();
-}
-uint32_t BinaryenGetNumExports(BinaryenModuleRef module) {
-  return ((Module*)module)->exports.size();
-}
-BinaryenExportRef BinaryenGetExportByIndex(BinaryenModuleRef module,
-                                           BinaryenIndex id) {
-  const auto& exports = ((Module*)module)->exports;
-  if (exports.size() <= id) {
-    Fatal() << "invalid export id.";
-  }
-  return exports[id].get();
 }
 
 //
diff --git a/binaryen/src/binaryen-c.h b/binaryen/src/binaryen-c.h
--- a/binaryen/src/binaryen-c.h
+++ b/binaryen/src/binaryen-c.h
@@ -25,7 +25,7 @@
 //   graph (CFG) as input.
 //
 // The final part of the API contains miscellaneous utilities like
-//   debugging/tracing for the API itself.
+//   debugging for the API itself.
 //
 // ---------------
 //
@@ -125,70 +125,12 @@
 typedef uint32_t BinaryenExpressionId;
 
 BINARYEN_API BinaryenExpressionId BinaryenInvalidId(void);
-BINARYEN_API BinaryenExpressionId BinaryenBlockId(void);
-BINARYEN_API BinaryenExpressionId BinaryenIfId(void);
-BINARYEN_API BinaryenExpressionId BinaryenLoopId(void);
-BINARYEN_API BinaryenExpressionId BinaryenBreakId(void);
-BINARYEN_API BinaryenExpressionId BinaryenSwitchId(void);
-BINARYEN_API BinaryenExpressionId BinaryenCallId(void);
-BINARYEN_API BinaryenExpressionId BinaryenCallIndirectId(void);
-BINARYEN_API BinaryenExpressionId BinaryenLocalGetId(void);
-BINARYEN_API BinaryenExpressionId BinaryenLocalSetId(void);
-BINARYEN_API BinaryenExpressionId BinaryenGlobalGetId(void);
-BINARYEN_API BinaryenExpressionId BinaryenGlobalSetId(void);
-BINARYEN_API BinaryenExpressionId BinaryenLoadId(void);
-BINARYEN_API BinaryenExpressionId BinaryenStoreId(void);
-BINARYEN_API BinaryenExpressionId BinaryenConstId(void);
-BINARYEN_API BinaryenExpressionId BinaryenUnaryId(void);
-BINARYEN_API BinaryenExpressionId BinaryenBinaryId(void);
-BINARYEN_API BinaryenExpressionId BinaryenSelectId(void);
-BINARYEN_API BinaryenExpressionId BinaryenDropId(void);
-BINARYEN_API BinaryenExpressionId BinaryenReturnId(void);
-BINARYEN_API BinaryenExpressionId BinaryenMemorySizeId(void);
-BINARYEN_API BinaryenExpressionId BinaryenMemoryGrowId(void);
-BINARYEN_API BinaryenExpressionId BinaryenNopId(void);
-BINARYEN_API BinaryenExpressionId BinaryenUnreachableId(void);
-BINARYEN_API BinaryenExpressionId BinaryenAtomicCmpxchgId(void);
-BINARYEN_API BinaryenExpressionId BinaryenAtomicRMWId(void);
-BINARYEN_API BinaryenExpressionId BinaryenAtomicWaitId(void);
-BINARYEN_API BinaryenExpressionId BinaryenAtomicNotifyId(void);
-BINARYEN_API BinaryenExpressionId BinaryenAtomicFenceId(void);
-BINARYEN_API BinaryenExpressionId BinaryenSIMDExtractId(void);
-BINARYEN_API BinaryenExpressionId BinaryenSIMDReplaceId(void);
-BINARYEN_API BinaryenExpressionId BinaryenSIMDShuffleId(void);
-BINARYEN_API BinaryenExpressionId BinaryenSIMDTernaryId(void);
-BINARYEN_API BinaryenExpressionId BinaryenSIMDShiftId(void);
-BINARYEN_API BinaryenExpressionId BinaryenSIMDLoadId(void);
-BINARYEN_API BinaryenExpressionId BinaryenMemoryInitId(void);
-BINARYEN_API BinaryenExpressionId BinaryenDataDropId(void);
-BINARYEN_API BinaryenExpressionId BinaryenMemoryCopyId(void);
-BINARYEN_API BinaryenExpressionId BinaryenMemoryFillId(void);
-BINARYEN_API BinaryenExpressionId BinaryenRefNullId(void);
-BINARYEN_API BinaryenExpressionId BinaryenRefIsNullId(void);
-BINARYEN_API BinaryenExpressionId BinaryenRefFuncId(void);
-BINARYEN_API BinaryenExpressionId BinaryenRefEqId(void);
-BINARYEN_API BinaryenExpressionId BinaryenTryId(void);
-BINARYEN_API BinaryenExpressionId BinaryenThrowId(void);
-BINARYEN_API BinaryenExpressionId BinaryenRethrowId(void);
-BINARYEN_API BinaryenExpressionId BinaryenBrOnExnId(void);
-BINARYEN_API BinaryenExpressionId BinaryenTupleMakeId(void);
-BINARYEN_API BinaryenExpressionId BinaryenTupleExtractId(void);
-BINARYEN_API BinaryenExpressionId BinaryenPopId(void);
-BINARYEN_API BinaryenExpressionId BinaryenI31NewId(void);
-BINARYEN_API BinaryenExpressionId BinaryenI31GetId(void);
-BINARYEN_API BinaryenExpressionId BinaryenRefTestId(void);
-BINARYEN_API BinaryenExpressionId BinaryenRefCastId(void);
-BINARYEN_API BinaryenExpressionId BinaryenBrOnCastId(void);
-BINARYEN_API BinaryenExpressionId BinaryenRttCanonId(void);
-BINARYEN_API BinaryenExpressionId BinaryenRttSubId(void);
-BINARYEN_API BinaryenExpressionId BinaryenStructNewId(void);
-BINARYEN_API BinaryenExpressionId BinaryenStructGetId(void);
-BINARYEN_API BinaryenExpressionId BinaryenStructSetId(void);
-BINARYEN_API BinaryenExpressionId BinaryenArrayNewId(void);
-BINARYEN_API BinaryenExpressionId BinaryenArrayGetId(void);
-BINARYEN_API BinaryenExpressionId BinaryenArraySetId(void);
-BINARYEN_API BinaryenExpressionId BinaryenArrayLenId(void);
 
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  BINARYEN_API BinaryenExpressionId Binaryen##CLASS_TO_VISIT##Id(void);
+
+#include "wasm-delegations.h"
+
 // External kinds (call to get the value of each; you can cache them)
 
 typedef uint32_t BinaryenExternalKind;
@@ -484,6 +426,7 @@
 BINARYEN_API BinaryenOp BinaryenXorVec128(void);
 BINARYEN_API BinaryenOp BinaryenAndNotVec128(void);
 BINARYEN_API BinaryenOp BinaryenBitselectVec128(void);
+// TODO: Add i8x16.popcnt to C and JS APIs once merged to the proposal
 BINARYEN_API BinaryenOp BinaryenAbsVecI8x16(void);
 BINARYEN_API BinaryenOp BinaryenNegVecI8x16(void);
 BINARYEN_API BinaryenOp BinaryenAnyTrueVecI8x16(void);
@@ -524,6 +467,8 @@
 BINARYEN_API BinaryenOp BinaryenMaxSVecI16x8(void);
 BINARYEN_API BinaryenOp BinaryenMaxUVecI16x8(void);
 BINARYEN_API BinaryenOp BinaryenAvgrUVecI16x8(void);
+// TODO: Add i16x8.q15mulr_sat_s to C and JS APIs once merged to the proposal
+// TODO: Add extending multiplications to APIs once they are merged as well
 BINARYEN_API BinaryenOp BinaryenAbsVecI32x4(void);
 BINARYEN_API BinaryenOp BinaryenNegVecI32x4(void);
 BINARYEN_API BinaryenOp BinaryenAnyTrueVecI32x4(void);
@@ -541,8 +486,6 @@
 BINARYEN_API BinaryenOp BinaryenMaxUVecI32x4(void);
 BINARYEN_API BinaryenOp BinaryenDotSVecI16x8ToVecI32x4(void);
 BINARYEN_API BinaryenOp BinaryenNegVecI64x2(void);
-BINARYEN_API BinaryenOp BinaryenAnyTrueVecI64x2(void);
-BINARYEN_API BinaryenOp BinaryenAllTrueVecI64x2(void);
 BINARYEN_API BinaryenOp BinaryenShlVecI64x2(void);
 BINARYEN_API BinaryenOp BinaryenShrSVecI64x2(void);
 BINARYEN_API BinaryenOp BinaryenShrUVecI64x2(void);
@@ -583,6 +526,7 @@
 BINARYEN_API BinaryenOp BinaryenFloorVecF64x2(void);
 BINARYEN_API BinaryenOp BinaryenTruncVecF64x2(void);
 BINARYEN_API BinaryenOp BinaryenNearestVecF64x2(void);
+// TODO: Add extending pairwise adds to C and JS APIs once merged
 BINARYEN_API BinaryenOp BinaryenTruncSatSVecF32x4ToVecI32x4(void);
 BINARYEN_API BinaryenOp BinaryenTruncSatUVecF32x4ToVecI32x4(void);
 BINARYEN_API BinaryenOp BinaryenTruncSatSVecF64x2ToVecI64x2(void);
@@ -847,7 +791,8 @@
 BINARYEN_API BinaryenExpressionRef
 BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef value);
 BINARYEN_API BinaryenExpressionRef BinaryenRefFunc(BinaryenModuleRef module,
-                                                   const char* func);
+                                                   const char* func,
+                                                   BinaryenType type);
 BINARYEN_API BinaryenExpressionRef BinaryenRefEq(BinaryenModuleRef module,
                                                  BinaryenExpressionRef left,
                                                  BinaryenExpressionRef right);
@@ -1459,47 +1404,47 @@
 
 // AtomicWait
 
-// Gets the pointer expression of an `atomic.wait` expression.
+// Gets the pointer expression of an `memory.atomic.wait` expression.
 BINARYEN_API BinaryenExpressionRef
 BinaryenAtomicWaitGetPtr(BinaryenExpressionRef expr);
-// Sets the pointer expression of an `atomic.wait` expression.
+// Sets the pointer expression of an `memory.atomic.wait` expression.
 BINARYEN_API void BinaryenAtomicWaitSetPtr(BinaryenExpressionRef expr,
                                            BinaryenExpressionRef ptrExpr);
-// Gets the expression representing the expected value of an `atomic.wait`
-// expression.
+// Gets the expression representing the expected value of an
+// `memory.atomic.wait` expression.
 BINARYEN_API BinaryenExpressionRef
 BinaryenAtomicWaitGetExpected(BinaryenExpressionRef expr);
-// Sets the expression representing the expected value of an `atomic.wait`
-// expression.
+// Sets the expression representing the expected value of an
+// `memory.atomic.wait` expression.
 BINARYEN_API void
 BinaryenAtomicWaitSetExpected(BinaryenExpressionRef expr,
                               BinaryenExpressionRef expectedExpr);
-// Gets the timeout expression of an `atomic.wait` expression.
+// Gets the timeout expression of an `memory.atomic.wait` expression.
 BINARYEN_API BinaryenExpressionRef
 BinaryenAtomicWaitGetTimeout(BinaryenExpressionRef expr);
-// Sets the timeout expression of an `atomic.wait` expression.
+// Sets the timeout expression of an `memory.atomic.wait` expression.
 BINARYEN_API void
 BinaryenAtomicWaitSetTimeout(BinaryenExpressionRef expr,
                              BinaryenExpressionRef timeoutExpr);
-// Gets the expected type of an `atomic.wait` expression.
+// Gets the expected type of an `memory.atomic.wait` expression.
 BINARYEN_API BinaryenType
 BinaryenAtomicWaitGetExpectedType(BinaryenExpressionRef expr);
-// Sets the expected type of an `atomic.wait` expression.
+// Sets the expected type of an `memory.atomic.wait` expression.
 BINARYEN_API void BinaryenAtomicWaitSetExpectedType(BinaryenExpressionRef expr,
                                                     BinaryenType expectedType);
 
 // AtomicNotify
 
-// Gets the pointer expression of an `atomic.notify` expression.
+// Gets the pointer expression of an `memory.atomic.notify` expression.
 BINARYEN_API BinaryenExpressionRef
 BinaryenAtomicNotifyGetPtr(BinaryenExpressionRef expr);
-// Sets the pointer expression of an `atomic.notify` expression.
+// Sets the pointer expression of an `memory.atomic.notify` expression.
 BINARYEN_API void BinaryenAtomicNotifySetPtr(BinaryenExpressionRef expr,
                                              BinaryenExpressionRef ptrExpr);
-// Gets the notify count expression of an `atomic.notify` expression.
+// Gets the notify count expression of an `memory.atomic.notify` expression.
 BINARYEN_API BinaryenExpressionRef
 BinaryenAtomicNotifyGetNotifyCount(BinaryenExpressionRef expr);
-// Sets the notify count expression of an `atomic.notify` expression.
+// Sets the notify count expression of an `memory.atomic.notify` expression.
 BINARYEN_API void
 BinaryenAtomicNotifySetNotifyCount(BinaryenExpressionRef expr,
                                    BinaryenExpressionRef notifyCountExpr);
@@ -1926,7 +1871,8 @@
                     BinaryenType* varTypes,
                     BinaryenIndex numVarTypes,
                     BinaryenExpressionRef body);
-// Gets a function reference by name.
+// Gets a function reference by name. Returns NULL if the function does not
+// exist.
 BINARYEN_API BinaryenFunctionRef BinaryenGetFunction(BinaryenModuleRef module,
                                                      const char* name);
 // Removes a function by name.
@@ -1934,10 +1880,10 @@
                                          const char* name);
 
 // Gets the number of functions in the module.
-BINARYEN_API uint32_t BinaryenGetNumFunctions(BinaryenModuleRef module);
-// Get function pointer from its index.
+BINARYEN_API BinaryenIndex BinaryenGetNumFunctions(BinaryenModuleRef module);
+// Gets the function at the specified index.
 BINARYEN_API BinaryenFunctionRef
-BinaryenGetFunctionByIndex(BinaryenModuleRef module, BinaryenIndex id);
+BinaryenGetFunctionByIndex(BinaryenModuleRef module, BinaryenIndex index);
 
 // Imports
 
@@ -1977,47 +1923,72 @@
 WASM_DEPRECATED BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module,
                                                     const char* internalName,
                                                     const char* externalName);
+// Adds a function export to the module.
 BINARYEN_API BinaryenExportRef BinaryenAddFunctionExport(
   BinaryenModuleRef module, const char* internalName, const char* externalName);
+// Adds a table export to the module.
 BINARYEN_API BinaryenExportRef BinaryenAddTableExport(BinaryenModuleRef module,
                                                       const char* internalName,
                                                       const char* externalName);
+// Adds a memory export to the module.
 BINARYEN_API BinaryenExportRef BinaryenAddMemoryExport(
   BinaryenModuleRef module, const char* internalName, const char* externalName);
+// Adds a global export to the module.
 BINARYEN_API BinaryenExportRef BinaryenAddGlobalExport(
   BinaryenModuleRef module, const char* internalName, const char* externalName);
+// Adds an event export to the module.
 BINARYEN_API BinaryenExportRef BinaryenAddEventExport(BinaryenModuleRef module,
                                                       const char* internalName,
                                                       const char* externalName);
+// Gets an export reference by external name. Returns NULL if the export does
+// not exist.
+BINARYEN_API BinaryenExportRef BinaryenGetExport(BinaryenModuleRef module,
+                                                 const char* externalName);
+// Removes an export by external name.
 BINARYEN_API void BinaryenRemoveExport(BinaryenModuleRef module,
                                        const char* externalName);
+// Gets the number of exports in the module.
+BINARYEN_API BinaryenIndex BinaryenGetNumExports(BinaryenModuleRef module);
+// Gets the export at the specified index.
+BINARYEN_API BinaryenExportRef
+BinaryenGetExportByIndex(BinaryenModuleRef module, BinaryenIndex index);
 
 // Globals
 
 BINARYEN_REF(Global);
 
+// Adds a global to the module.
 BINARYEN_API BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module,
                                                  const char* name,
                                                  BinaryenType type,
                                                  int8_t mutable_,
                                                  BinaryenExpressionRef init);
-// Gets a global reference by name.
+// Gets a global reference by name. Returns NULL if the global does not exist.
 BINARYEN_API BinaryenGlobalRef BinaryenGetGlobal(BinaryenModuleRef module,
                                                  const char* name);
+// Removes a global by name.
 BINARYEN_API void BinaryenRemoveGlobal(BinaryenModuleRef module,
                                        const char* name);
+// Gets the number of globals in the module.
+BINARYEN_API BinaryenIndex BinaryenGetNumGlobals(BinaryenModuleRef module);
+// Gets the global at the specified index.
+BINARYEN_API BinaryenGlobalRef
+BinaryenGetGlobalByIndex(BinaryenModuleRef module, BinaryenIndex index);
 
 // Events
 
 BINARYEN_REF(Event);
 
+// Adds an event to the module.
 BINARYEN_API BinaryenEventRef BinaryenAddEvent(BinaryenModuleRef module,
                                                const char* name,
                                                uint32_t attribute,
                                                BinaryenType params,
                                                BinaryenType results);
+// Gets an event reference by name. Returns NULL if the event does not exist.
 BINARYEN_API BinaryenEventRef BinaryenGetEvent(BinaryenModuleRef module,
                                                const char* name);
+// Removes an event by name.
 BINARYEN_API void BinaryenRemoveEvent(BinaryenModuleRef module,
                                       const char* name);
 
@@ -2385,11 +2356,6 @@
 BINARYEN_API const char* BinaryenExportGetName(BinaryenExportRef export_);
 // Gets the internal name of the specified export.
 BINARYEN_API const char* BinaryenExportGetValue(BinaryenExportRef export_);
-// Gets the number of exports in the module.
-BINARYEN_API uint32_t BinaryenGetNumExports(BinaryenModuleRef module);
-// Get export pointer from its index.
-BINARYEN_API BinaryenExportRef
-BinaryenGetExportByIndex(BinaryenModuleRef module, BinaryenIndex id);
 
 //
 // ========= Custom sections =========
@@ -2549,10 +2515,10 @@
 // ========= Utilities =========
 //
 
-// Enable or disable coloring for the WASM printer
+// Enable or disable coloring for the Wasm printer
 BINARYEN_API void BinaryenSetColorsEnabled(int enabled);
 
-// Query whether color is enable for the WASM printer
+// Query whether color is enable for the Wasm printer
 BINARYEN_API int BinaryenAreColorsEnabled();
 #ifdef __cplusplus
 } // extern "C"
diff --git a/binaryen/src/config.h b/binaryen/src/config.h
--- a/binaryen/src/config.h
+++ b/binaryen/src/config.h
@@ -1,1 +1,1 @@
-#define PROJECT_VERSION "98"
+#define PROJECT_VERSION "98 (version_99)"
diff --git a/binaryen/src/dataflow/utils.h b/binaryen/src/dataflow/utils.h
--- a/binaryen/src/dataflow/utils.h
+++ b/binaryen/src/dataflow/utils.h
@@ -26,7 +26,6 @@
 #define wasm_dataflow_utils_h
 
 #include "dataflow/node.h"
-#include "wasm-printing.h"
 #include "wasm.h"
 
 namespace wasm {
@@ -47,7 +46,7 @@
       break;
     case Node::Type::Expr: {
       o << "expr ";
-      WasmPrinter::printExpression(node->expr, o, true);
+      o << *node->expr << '\n';
       break;
     }
     case Node::Type::Phi:
diff --git a/binaryen/src/gen-s-parser.inc b/binaryen/src/gen-s-parser.inc
--- a/binaryen/src/gen-s-parser.inc
+++ b/binaryen/src/gen-s-parser.inc
@@ -4,8 +4,8 @@
 
 #ifdef INSTRUCTION_PARSER
 #undef INSTRUCTION_PARSER
-char op[28] = {'\0'};
-strncpy(op, s[0]->c_str(), 27);
+char op[30] = {'\0'};
+strncpy(op, s[0]->c_str(), 29);
 switch (op[0]) {
   case 'a': {
     switch (op[1]) {
@@ -50,17 +50,9 @@
           default: goto parse_error;
         }
       }
-      case 't': {
-        switch (op[7]) {
-          case 'f':
-            if (strcmp(op, "atomic.fence") == 0) { return makeAtomicFence(s); }
-            goto parse_error;
-          case 'n':
-            if (strcmp(op, "atomic.notify") == 0) { return makeAtomicNotify(s); }
-            goto parse_error;
-          default: goto parse_error;
-        }
-      }
+      case 't':
+        if (strcmp(op, "atomic.fence") == 0) { return makeAtomicFence(s); }
+        goto parse_error;
       default: goto parse_error;
     }
   }
@@ -107,9 +99,17 @@
       case '\0':
         if (strcmp(op, "call") == 0) { return makeCall(s, /*isReturn=*/false); }
         goto parse_error;
-      case '_':
-        if (strcmp(op, "call_indirect") == 0) { return makeCallIndirect(s, /*isReturn=*/false); }
-        goto parse_error;
+      case '_': {
+        switch (op[5]) {
+          case 'i':
+            if (strcmp(op, "call_indirect") == 0) { return makeCallIndirect(s, /*isReturn=*/false); }
+            goto parse_error;
+          case 'r':
+            if (strcmp(op, "call_ref") == 0) { return makeCallRef(s, /*isReturn=*/false); }
+            goto parse_error;
+          default: goto parse_error;
+        }
+      }
       default: goto parse_error;
     }
   }
@@ -799,13 +799,56 @@
                 if (strcmp(op, "i16x8.eq") == 0) { return makeBinary(s, BinaryOp::EqVecI16x8); }
                 goto parse_error;
               case 'x': {
-                switch (op[19]) {
-                  case 's':
-                    if (strcmp(op, "i16x8.extract_lane_s") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneSVecI16x8, 8); }
-                    goto parse_error;
-                  case 'u':
-                    if (strcmp(op, "i16x8.extract_lane_u") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneUVecI16x8, 8); }
-                    goto parse_error;
+                switch (op[9]) {
+                  case 'a': {
+                    switch (op[28]) {
+                      case 's':
+                        if (strcmp(op, "i16x8.extadd_pairwise_i8x16_s") == 0) { return makeUnary(s, UnaryOp::ExtAddPairwiseSVecI8x16ToI16x8); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i16x8.extadd_pairwise_i8x16_u") == 0) { return makeUnary(s, UnaryOp::ExtAddPairwiseUVecI8x16ToI16x8); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'm': {
+                    switch (op[13]) {
+                      case 'h': {
+                        switch (op[24]) {
+                          case 's':
+                            if (strcmp(op, "i16x8.extmul_high_i8x16_s") == 0) { return makeBinary(s, BinaryOp::ExtMulHighSVecI16x8); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i16x8.extmul_high_i8x16_u") == 0) { return makeBinary(s, BinaryOp::ExtMulHighUVecI16x8); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'l': {
+                        switch (op[23]) {
+                          case 's':
+                            if (strcmp(op, "i16x8.extmul_low_i8x16_s") == 0) { return makeBinary(s, BinaryOp::ExtMulLowSVecI16x8); }
+                            goto parse_error;
+                          case 'u':
+                            if (strcmp(op, "i16x8.extmul_low_i8x16_u") == 0) { return makeBinary(s, BinaryOp::ExtMulLowUVecI16x8); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'r': {
+                    switch (op[19]) {
+                      case 's':
+                        if (strcmp(op, "i16x8.extract_lane_s") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneSVecI16x8, 8); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i16x8.extract_lane_u") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneUVecI16x8, 8); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
                   default: goto parse_error;
                 }
               }
@@ -934,6 +977,9 @@
               default: goto parse_error;
             }
           }
+          case 'q':
+            if (strcmp(op, "i16x8.q15mulr_sat_s") == 0) { return makeBinary(s, BinaryOp::Q15MulrSatSVecI16x8); }
+            goto parse_error;
           case 'r':
             if (strcmp(op, "i16x8.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI16x8, 8); }
             goto parse_error;
@@ -1189,9 +1235,6 @@
                               default: goto parse_error;
                             }
                           }
-                          case 'w':
-                            if (strcmp(op, "i32.atomic.wait") == 0) { return makeAtomicWait(s, Type::i32); }
-                            goto parse_error;
                           default: goto parse_error;
                         }
                       }
@@ -1520,9 +1563,52 @@
                       case 'q':
                         if (strcmp(op, "i32x4.eq") == 0) { return makeBinary(s, BinaryOp::EqVecI32x4); }
                         goto parse_error;
-                      case 'x':
-                        if (strcmp(op, "i32x4.extract_lane") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecI32x4, 4); }
-                        goto parse_error;
+                      case 'x': {
+                        switch (op[9]) {
+                          case 'a': {
+                            switch (op[28]) {
+                              case 's':
+                                if (strcmp(op, "i32x4.extadd_pairwise_i16x8_s") == 0) { return makeUnary(s, UnaryOp::ExtAddPairwiseSVecI16x8ToI32x4); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i32x4.extadd_pairwise_i16x8_u") == 0) { return makeUnary(s, UnaryOp::ExtAddPairwiseUVecI16x8ToI32x4); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          case 'm': {
+                            switch (op[13]) {
+                              case 'h': {
+                                switch (op[24]) {
+                                  case 's':
+                                    if (strcmp(op, "i32x4.extmul_high_i16x8_s") == 0) { return makeBinary(s, BinaryOp::ExtMulHighSVecI32x4); }
+                                    goto parse_error;
+                                  case 'u':
+                                    if (strcmp(op, "i32x4.extmul_high_i16x8_u") == 0) { return makeBinary(s, BinaryOp::ExtMulHighUVecI32x4); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              case 'l': {
+                                switch (op[23]) {
+                                  case 's':
+                                    if (strcmp(op, "i32x4.extmul_low_i16x8_s") == 0) { return makeBinary(s, BinaryOp::ExtMulLowSVecI32x4); }
+                                    goto parse_error;
+                                  case 'u':
+                                    if (strcmp(op, "i32x4.extmul_low_i16x8_u") == 0) { return makeBinary(s, BinaryOp::ExtMulLowUVecI32x4); }
+                                    goto parse_error;
+                                  default: goto parse_error;
+                                }
+                              }
+                              default: goto parse_error;
+                            }
+                          }
+                          case 'r':
+                            if (strcmp(op, "i32x4.extract_lane") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecI32x4, 4); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
                       default: goto parse_error;
                     }
                   }
@@ -1909,9 +1995,6 @@
                           default: goto parse_error;
                         }
                       }
-                      case 'w':
-                        if (strcmp(op, "i64.atomic.wait") == 0) { return makeAtomicWait(s, Type::i64); }
-                        goto parse_error;
                       default: goto parse_error;
                     }
                   }
@@ -2237,23 +2320,55 @@
           }
           case 'x': {
             switch (op[6]) {
-              case 'a': {
+              case 'a':
+                if (strcmp(op, "i64x2.add") == 0) { return makeBinary(s, BinaryOp::AddVecI64x2); }
+                goto parse_error;
+              case 'b':
+                if (strcmp(op, "i64x2.bitmask") == 0) { return makeUnary(s, UnaryOp::BitmaskVecI64x2); }
+                goto parse_error;
+              case 'e': {
                 switch (op[7]) {
-                  case 'd':
-                    if (strcmp(op, "i64x2.add") == 0) { return makeBinary(s, BinaryOp::AddVecI64x2); }
-                    goto parse_error;
-                  case 'l':
-                    if (strcmp(op, "i64x2.all_true") == 0) { return makeUnary(s, UnaryOp::AllTrueVecI64x2); }
-                    goto parse_error;
-                  case 'n':
-                    if (strcmp(op, "i64x2.any_true") == 0) { return makeUnary(s, UnaryOp::AnyTrueVecI64x2); }
+                  case 'q':
+                    if (strcmp(op, "i64x2.eq") == 0) { return makeBinary(s, BinaryOp::EqVecI64x2); }
                     goto parse_error;
+                  case 'x': {
+                    switch (op[9]) {
+                      case 'm': {
+                        switch (op[13]) {
+                          case 'h': {
+                            switch (op[24]) {
+                              case 's':
+                                if (strcmp(op, "i64x2.extmul_high_i32x4_s") == 0) { return makeBinary(s, BinaryOp::ExtMulHighSVecI64x2); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i64x2.extmul_high_i32x4_u") == 0) { return makeBinary(s, BinaryOp::ExtMulHighUVecI64x2); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          case 'l': {
+                            switch (op[23]) {
+                              case 's':
+                                if (strcmp(op, "i64x2.extmul_low_i32x4_s") == 0) { return makeBinary(s, BinaryOp::ExtMulLowSVecI64x2); }
+                                goto parse_error;
+                              case 'u':
+                                if (strcmp(op, "i64x2.extmul_low_i32x4_u") == 0) { return makeBinary(s, BinaryOp::ExtMulLowUVecI64x2); }
+                                goto parse_error;
+                              default: goto parse_error;
+                            }
+                          }
+                          default: goto parse_error;
+                        }
+                      }
+                      case 'r':
+                        if (strcmp(op, "i64x2.extract_lane") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecI64x2, 2); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
                   default: goto parse_error;
                 }
               }
-              case 'e':
-                if (strcmp(op, "i64x2.extract_lane") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecI64x2, 2); }
-                goto parse_error;
               case 'l': {
                 switch (op[15]) {
                   case 's':
@@ -2315,6 +2430,33 @@
                   default: goto parse_error;
                 }
               }
+              case 'w': {
+                switch (op[12]) {
+                  case 'h': {
+                    switch (op[23]) {
+                      case 's':
+                        if (strcmp(op, "i64x2.widen_high_i32x4_s") == 0) { return makeUnary(s, UnaryOp::WidenHighSVecI32x4ToVecI64x2); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i64x2.widen_high_i32x4_u") == 0) { return makeUnary(s, UnaryOp::WidenHighUVecI32x4ToVecI64x2); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case 'l': {
+                    switch (op[22]) {
+                      case 's':
+                        if (strcmp(op, "i64x2.widen_low_i32x4_s") == 0) { return makeUnary(s, UnaryOp::WidenLowSVecI32x4ToVecI64x2); }
+                        goto parse_error;
+                      case 'u':
+                        if (strcmp(op, "i64x2.widen_low_i32x4_u") == 0) { return makeUnary(s, UnaryOp::WidenLowUVecI32x4ToVecI64x2); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  default: goto parse_error;
+                }
+              }
               default: goto parse_error;
             }
           }
@@ -2492,6 +2634,9 @@
               default: goto parse_error;
             }
           }
+          case 'p':
+            if (strcmp(op, "i8x16.popcnt") == 0) { return makeUnary(s, UnaryOp::PopcntVecI8x16); }
+            goto parse_error;
           case 'r':
             if (strcmp(op, "i8x16.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI8x16, 16); }
             goto parse_error;
@@ -2574,6 +2719,25 @@
   }
   case 'm': {
     switch (op[7]) {
+      case 'a': {
+        switch (op[14]) {
+          case 'n':
+            if (strcmp(op, "memory.atomic.notify") == 0) { return makeAtomicNotify(s); }
+            goto parse_error;
+          case 'w': {
+            switch (op[18]) {
+              case '3':
+                if (strcmp(op, "memory.atomic.wait32") == 0) { return makeAtomicWait(s, Type::i32); }
+                goto parse_error;
+              case '6':
+                if (strcmp(op, "memory.atomic.wait64") == 0) { return makeAtomicWait(s, Type::i64); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
       case 'c':
         if (strcmp(op, "memory.copy") == 0) { return makeMemoryCopy(s); }
         goto parse_error;
@@ -2595,9 +2759,25 @@
   case 'n':
     if (strcmp(op, "nop") == 0) { return makeNop(); }
     goto parse_error;
-  case 'p':
-    if (strcmp(op, "pop") == 0) { return makePop(s); }
-    goto parse_error;
+  case 'p': {
+    switch (op[1]) {
+      case 'o':
+        if (strcmp(op, "pop") == 0) { return makePop(s); }
+        goto parse_error;
+      case 'r': {
+        switch (op[9]) {
+          case 'n':
+            if (strcmp(op, "prefetch.nt") == 0) { return makePrefetch(s, PrefetchOp::PrefetchNontemporal); }
+            goto parse_error;
+          case 't':
+            if (strcmp(op, "prefetch.t") == 0) { return makePrefetch(s, PrefetchOp::PrefetchTemporal); }
+            goto parse_error;
+          default: goto parse_error;
+        }
+      }
+      default: goto parse_error;
+    }
+  }
   case 'r': {
     switch (op[1]) {
       case 'e': {
@@ -2640,9 +2820,17 @@
                       case '\0':
                         if (strcmp(op, "return_call") == 0) { return makeCall(s, /*isReturn=*/true); }
                         goto parse_error;
-                      case '_':
-                        if (strcmp(op, "return_call_indirect") == 0) { return makeCallIndirect(s, /*isReturn=*/true); }
-                        goto parse_error;
+                      case '_': {
+                        switch (op[12]) {
+                          case 'i':
+                            if (strcmp(op, "return_call_indirect") == 0) { return makeCallIndirect(s, /*isReturn=*/true); }
+                            goto parse_error;
+                          case 'r':
+                            if (strcmp(op, "return_call_ref") == 0) { return makeCallRef(s, /*isReturn=*/true); }
+                            goto parse_error;
+                          default: goto parse_error;
+                        }
+                      }
                       default: goto parse_error;
                     }
                   }
@@ -2776,11 +2964,33 @@
                   case '\0':
                     if (strcmp(op, "v128.load") == 0) { return makeLoad(s, Type::v128, /*isAtomic=*/false); }
                     goto parse_error;
-                  case '3':
-                    if (strcmp(op, "v128.load32_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load32Zero); }
+                  case '1':
+                    if (strcmp(op, "v128.load16_lane") == 0) { return makeSIMDLoadStoreLane(s, LoadLaneVec16x8); }
                     goto parse_error;
-                  case '6':
-                    if (strcmp(op, "v128.load64_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load64Zero); }
+                  case '3': {
+                    switch (op[12]) {
+                      case 'l':
+                        if (strcmp(op, "v128.load32_lane") == 0) { return makeSIMDLoadStoreLane(s, LoadLaneVec32x4); }
+                        goto parse_error;
+                      case 'z':
+                        if (strcmp(op, "v128.load32_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load32Zero); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case '6': {
+                    switch (op[12]) {
+                      case 'l':
+                        if (strcmp(op, "v128.load64_lane") == 0) { return makeSIMDLoadStoreLane(s, LoadLaneVec64x2); }
+                        goto parse_error;
+                      case 'z':
+                        if (strcmp(op, "v128.load64_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load64Zero); }
+                        goto parse_error;
+                      default: goto parse_error;
+                    }
+                  }
+                  case '8':
+                    if (strcmp(op, "v128.load8_lane") == 0) { return makeSIMDLoadStoreLane(s, LoadLaneVec8x16); }
                     goto parse_error;
                   default: goto parse_error;
                 }
@@ -2791,27 +3001,68 @@
               case 'o':
                 if (strcmp(op, "v128.or") == 0) { return makeBinary(s, BinaryOp::OrVec128); }
                 goto parse_error;
-              case 's':
-                if (strcmp(op, "v128.store") == 0) { return makeStore(s, Type::v128, /*isAtomic=*/false); }
-                goto parse_error;
+              case 's': {
+                switch (op[10]) {
+                  case '\0':
+                    if (strcmp(op, "v128.store") == 0) { return makeStore(s, Type::v128, /*isAtomic=*/false); }
+                    goto parse_error;
+                  case '1':
+                    if (strcmp(op, "v128.store16_lane") == 0) { return makeSIMDLoadStoreLane(s, StoreLaneVec16x8); }
+                    goto parse_error;
+                  case '3':
+                    if (strcmp(op, "v128.store32_lane") == 0) { return makeSIMDLoadStoreLane(s, StoreLaneVec32x4); }
+                    goto parse_error;
+                  case '6':
+                    if (strcmp(op, "v128.store64_lane") == 0) { return makeSIMDLoadStoreLane(s, StoreLaneVec64x2); }
+                    goto parse_error;
+                  case '8':
+                    if (strcmp(op, "v128.store8_lane") == 0) { return makeSIMDLoadStoreLane(s, StoreLaneVec8x16); }
+                    goto parse_error;
+                  default: goto parse_error;
+                }
+              }
               case 'x':
                 if (strcmp(op, "v128.xor") == 0) { return makeBinary(s, BinaryOp::XorVec128); }
                 goto parse_error;
               default: goto parse_error;
             }
           }
-          case '6':
-            if (strcmp(op, "v16x8.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec16x8); }
+          case '6': {
+            switch (op[6]) {
+              case 'l':
+                if (strcmp(op, "v16x8.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec16x8); }
+                goto parse_error;
+              case 's':
+                if (strcmp(op, "v16x8.signselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec16x8); }
+                goto parse_error;
+              default: goto parse_error;
+            }
+          }
+          default: goto parse_error;
+        }
+      }
+      case '3': {
+        switch (op[6]) {
+          case 'l':
+            if (strcmp(op, "v32x4.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec32x4); }
             goto parse_error;
+          case 's':
+            if (strcmp(op, "v32x4.signselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec32x4); }
+            goto parse_error;
           default: goto parse_error;
         }
       }
-      case '3':
-        if (strcmp(op, "v32x4.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec32x4); }
-        goto parse_error;
-      case '6':
-        if (strcmp(op, "v64x2.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec64x2); }
-        goto parse_error;
+      case '6': {
+        switch (op[6]) {
+          case 'l':
+            if (strcmp(op, "v64x2.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec64x2); }
+            goto parse_error;
+          case 's':
+            if (strcmp(op, "v64x2.signselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec64x2); }
+            goto parse_error;
+          default: goto parse_error;
+        }
+      }
       case '8': {
         switch (op[6]) {
           case 'l':
@@ -2821,6 +3072,9 @@
             switch (op[7]) {
               case 'h':
                 if (strcmp(op, "v8x16.shuffle") == 0) { return makeSIMDShuffle(s); }
+                goto parse_error;
+              case 'i':
+                if (strcmp(op, "v8x16.signselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec8x16); }
                 goto parse_error;
               case 'w':
                 if (strcmp(op, "v8x16.swizzle") == 0) { return makeBinary(s, BinaryOp::SwizzleVec8x16); }
diff --git a/binaryen/src/ir/CMakeLists.txt b/binaryen/src/ir/CMakeLists.txt
--- a/binaryen/src/ir/CMakeLists.txt
+++ b/binaryen/src/ir/CMakeLists.txt
@@ -5,6 +5,7 @@
   LocalGraph.cpp
   ReFinalize.cpp
   stack-utils.cpp
+  module-splitting.cpp
   ${ir_HEADERS}
 )
 add_library(ir OBJECT ${ir_SOURCES})
diff --git a/binaryen/src/ir/ExpressionAnalyzer.cpp b/binaryen/src/ir/ExpressionAnalyzer.cpp
--- a/binaryen/src/ir/ExpressionAnalyzer.cpp
+++ b/binaryen/src/ir/ExpressionAnalyzer.cpp
@@ -96,186 +96,6 @@
   return false;
 }
 
-//
-// Allows visiting the immediate fields of the expression. This is
-// useful for comparisons and hashing.
-//
-// The passed-in visitor object must implement:
-//  * visitScopeName - a Name that represents a block or loop scope
-//  * visitNonScopeName - a non-scope name
-//  * visitInt - anything that has a short enumeration, including
-//               opcodes, # of bytes in a load, bools, etc. - must be
-//               guaranteed to fit in an int32 or less.
-//  * visitLiteral - a Literal
-//  * visitType - a Type
-//  * visitIndex - an Index
-//  * visitAddress - an Address
-//
-
-namespace {
-
-template<typename T> void visitImmediates(Expression* curr, T& visitor) {
-  struct ImmediateVisitor : public OverriddenVisitor<ImmediateVisitor> {
-    T& visitor;
-
-    ImmediateVisitor(Expression* curr, T& visitor) : visitor(visitor) {
-      this->visit(curr);
-    }
-
-    void visitBlock(Block* curr) { visitor.visitScopeName(curr->name); }
-    void visitIf(If* curr) {}
-    void visitLoop(Loop* curr) { visitor.visitScopeName(curr->name); }
-    void visitBreak(Break* curr) { visitor.visitScopeName(curr->name); }
-    void visitSwitch(Switch* curr) {
-      for (auto target : curr->targets) {
-        visitor.visitScopeName(target);
-      }
-      visitor.visitScopeName(curr->default_);
-    }
-    void visitCall(Call* curr) {
-      visitor.visitNonScopeName(curr->target);
-      visitor.visitInt(curr->isReturn);
-    }
-    void visitCallIndirect(CallIndirect* curr) {
-      visitor.visitInt(curr->sig.params.getID());
-      visitor.visitInt(curr->sig.results.getID());
-      visitor.visitInt(curr->isReturn);
-    }
-    void visitLocalGet(LocalGet* curr) { visitor.visitIndex(curr->index); }
-    void visitLocalSet(LocalSet* curr) { visitor.visitIndex(curr->index); }
-    void visitGlobalGet(GlobalGet* curr) {
-      visitor.visitNonScopeName(curr->name);
-    }
-    void visitGlobalSet(GlobalSet* curr) {
-      visitor.visitNonScopeName(curr->name);
-    }
-    void visitLoad(Load* curr) {
-      visitor.visitInt(curr->bytes);
-      if (curr->type != Type::unreachable &&
-          curr->bytes < curr->type.getByteSize()) {
-        visitor.visitInt(curr->signed_);
-      }
-      visitor.visitAddress(curr->offset);
-      visitor.visitAddress(curr->align);
-      visitor.visitInt(curr->isAtomic);
-    }
-    void visitStore(Store* curr) {
-      visitor.visitInt(curr->bytes);
-      visitor.visitAddress(curr->offset);
-      visitor.visitAddress(curr->align);
-      visitor.visitInt(curr->isAtomic);
-      visitor.visitInt(curr->valueType.getID());
-    }
-    void visitAtomicRMW(AtomicRMW* curr) {
-      visitor.visitInt(curr->op);
-      visitor.visitInt(curr->bytes);
-      visitor.visitAddress(curr->offset);
-    }
-    void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
-      visitor.visitInt(curr->bytes);
-      visitor.visitAddress(curr->offset);
-    }
-    void visitAtomicWait(AtomicWait* curr) {
-      visitor.visitAddress(curr->offset);
-      visitor.visitType(curr->expectedType);
-    }
-    void visitAtomicNotify(AtomicNotify* curr) {
-      visitor.visitAddress(curr->offset);
-    }
-    void visitAtomicFence(AtomicFence* curr) { visitor.visitInt(curr->order); }
-    void visitSIMDExtract(SIMDExtract* curr) {
-      visitor.visitInt(curr->op);
-      visitor.visitInt(curr->index);
-    }
-    void visitSIMDReplace(SIMDReplace* curr) {
-      visitor.visitInt(curr->op);
-      visitor.visitInt(curr->index);
-    }
-    void visitSIMDShuffle(SIMDShuffle* curr) {
-      for (auto x : curr->mask) {
-        visitor.visitInt(x);
-      }
-    }
-    void visitSIMDTernary(SIMDTernary* curr) { visitor.visitInt(curr->op); }
-    void visitSIMDShift(SIMDShift* curr) { visitor.visitInt(curr->op); }
-    void visitSIMDLoad(SIMDLoad* curr) {
-      visitor.visitInt(curr->op);
-      visitor.visitAddress(curr->offset);
-      visitor.visitAddress(curr->align);
-    }
-    void visitMemoryInit(MemoryInit* curr) {
-      visitor.visitIndex(curr->segment);
-    }
-    void visitDataDrop(DataDrop* curr) { visitor.visitIndex(curr->segment); }
-    void visitMemoryCopy(MemoryCopy* curr) {}
-    void visitMemoryFill(MemoryFill* curr) {}
-    void visitConst(Const* curr) { visitor.visitLiteral(curr->value); }
-    void visitUnary(Unary* curr) { visitor.visitInt(curr->op); }
-    void visitBinary(Binary* curr) { visitor.visitInt(curr->op); }
-    void visitSelect(Select* curr) {}
-    void visitDrop(Drop* curr) {}
-    void visitReturn(Return* curr) {}
-    void visitMemorySize(MemorySize* curr) {}
-    void visitMemoryGrow(MemoryGrow* curr) {}
-    void visitRefNull(RefNull* curr) { visitor.visitType(curr->type); }
-    void visitRefIsNull(RefIsNull* curr) {}
-    void visitRefFunc(RefFunc* curr) { visitor.visitNonScopeName(curr->func); }
-    void visitRefEq(RefEq* curr) {}
-    void visitTry(Try* curr) {}
-    void visitThrow(Throw* curr) { visitor.visitNonScopeName(curr->event); }
-    void visitRethrow(Rethrow* curr) {}
-    void visitBrOnExn(BrOnExn* curr) {
-      visitor.visitScopeName(curr->name);
-      visitor.visitNonScopeName(curr->event);
-    }
-    void visitNop(Nop* curr) {}
-    void visitUnreachable(Unreachable* curr) {}
-    void visitPop(Pop* curr) {}
-    void visitTupleMake(TupleMake* curr) {}
-    void visitTupleExtract(TupleExtract* curr) {
-      visitor.visitIndex(curr->index);
-    }
-    void visitI31New(I31New* curr) {}
-    void visitI31Get(I31Get* curr) { visitor.visitInt(curr->signed_); }
-    void visitRefTest(RefTest* curr) {
-      WASM_UNREACHABLE("TODO (gc): ref.test");
-    }
-    void visitRefCast(RefCast* curr) {
-      WASM_UNREACHABLE("TODO (gc): ref.cast");
-    }
-    void visitBrOnCast(BrOnCast* curr) {
-      WASM_UNREACHABLE("TODO (gc): br_on_cast");
-    }
-    void visitRttCanon(RttCanon* curr) {
-      WASM_UNREACHABLE("TODO (gc): rtt.canon");
-    }
-    void visitRttSub(RttSub* curr) { WASM_UNREACHABLE("TODO (gc): rtt.sub"); }
-    void visitStructNew(StructNew* curr) {
-      WASM_UNREACHABLE("TODO (gc): struct.new");
-    }
-    void visitStructGet(StructGet* curr) {
-      WASM_UNREACHABLE("TODO (gc): struct.get");
-    }
-    void visitStructSet(StructSet* curr) {
-      WASM_UNREACHABLE("TODO (gc): struct.set");
-    }
-    void visitArrayNew(ArrayNew* curr) {
-      WASM_UNREACHABLE("TODO (gc): array.new");
-    }
-    void visitArrayGet(ArrayGet* curr) {
-      WASM_UNREACHABLE("TODO (gc): array.get");
-    }
-    void visitArraySet(ArraySet* curr) {
-      WASM_UNREACHABLE("TODO (gc): array.set");
-    }
-    void visitArrayLen(ArrayLen* curr) {
-      WASM_UNREACHABLE("TODO (gc): array.len");
-    }
-  } singleton(curr, visitor);
-}
-
-} // namespace
-
 bool ExpressionAnalyzer::flexibleEqual(Expression* left,
                                        Expression* right,
                                        ExprComparer comparer) {
@@ -285,80 +105,6 @@
     std::vector<Expression*> leftStack;
     std::vector<Expression*> rightStack;
 
-    struct Immediates {
-      Comparer& parent;
-
-      Immediates(Comparer& parent) : parent(parent) {}
-
-      SmallVector<Name, 1> scopeNames;
-      SmallVector<Name, 1> nonScopeNames;
-      SmallVector<int32_t, 3> ints;
-      SmallVector<Literal, 1> literals;
-      SmallVector<Type, 1> types;
-      SmallVector<Index, 1> indexes;
-      SmallVector<Address, 2> addresses;
-
-      void visitScopeName(Name curr) { scopeNames.push_back(curr); }
-      void visitNonScopeName(Name curr) { nonScopeNames.push_back(curr); }
-      void visitInt(int32_t curr) { ints.push_back(curr); }
-      void visitLiteral(Literal curr) { literals.push_back(curr); }
-      void visitType(Type curr) { types.push_back(curr); }
-      void visitIndex(Index curr) { indexes.push_back(curr); }
-      void visitAddress(Address curr) { addresses.push_back(curr); }
-
-      // Comparison is by value, except for names, which must match.
-      bool operator==(const Immediates& other) {
-        if (scopeNames.size() != other.scopeNames.size()) {
-          return false;
-        }
-        for (Index i = 0; i < scopeNames.size(); i++) {
-          auto leftName = scopeNames[i];
-          auto rightName = other.scopeNames[i];
-          auto iter = parent.rightNames.find(leftName);
-          // If it's not found, that means it was defined out of the expression
-          // being compared, in which case we can just treat it literally - it
-          // must be exactly identical.
-          if (iter != parent.rightNames.end()) {
-            leftName = iter->second;
-          }
-          if (leftName != rightName) {
-            return false;
-          }
-        }
-        if (nonScopeNames != other.nonScopeNames) {
-          return false;
-        }
-        if (ints != other.ints) {
-          return false;
-        }
-        if (literals != other.literals) {
-          return false;
-        }
-        if (types != other.types) {
-          return false;
-        }
-        if (indexes != other.indexes) {
-          return false;
-        }
-        if (addresses != other.addresses) {
-          return false;
-        }
-        return true;
-      }
-
-      bool operator!=(const Immediates& other) { return !(*this == other); }
-
-      void clear() {
-        scopeNames.clear();
-        nonScopeNames.clear();
-        ints.clear();
-        literals.clear();
-        types.clear();
-        indexes.clear();
-        addresses.clear();
-      }
-    };
-
     bool noteNames(Name left, Name right) {
       if (left.is() != right.is()) {
         return false;
@@ -371,8 +117,6 @@
     }
 
     bool compare(Expression* left, Expression* right, ExprComparer comparer) {
-      Immediates leftImmediates(*this), rightImmediates(*this);
-
       // The empty name is the same on both sides.
       rightNames[Name()] = Name();
 
@@ -390,45 +134,16 @@
         if (!left) {
           continue;
         }
+        // There are actual expressions to compare here. Start with the custom
+        // comparer function that was provided.
         if (comparer(left, right)) {
-          continue; // comparison hook, before all the rest
+          continue;
         }
-        // continue with normal structural comparison
-        if (left->_id != right->_id) {
+        if (left->type != right->type) {
           return false;
         }
-        // Blocks and loops introduce scoping.
-        if (auto* block = left->dynCast<Block>()) {
-          if (!noteNames(block->name, right->cast<Block>()->name)) {
-            return false;
-          }
-        } else if (auto* loop = left->dynCast<Loop>()) {
-          if (!noteNames(loop->name, right->cast<Loop>()->name)) {
-            return false;
-          }
-        } else {
-          // For all other nodes, compare their immediate values
-          visitImmediates(left, leftImmediates);
-          visitImmediates(right, rightImmediates);
-          if (leftImmediates != rightImmediates) {
-            return false;
-          }
-          leftImmediates.clear();
-          rightImmediates.clear();
-        }
-        // Add child nodes.
-        Index counter = 0;
-        for (auto* child : ChildIterator(left)) {
-          leftStack.push_back(child);
-          counter++;
-        }
-        for (auto* child : ChildIterator(right)) {
-          rightStack.push_back(child);
-          counter--;
-        }
-        // The number of child nodes must match (e.g. return has an optional
-        // one).
-        if (counter != 0) {
+        // Do the actual comparison, updating the names and stacks accordingly.
+        if (!compareNodes(left, right)) {
           return false;
         }
       }
@@ -437,6 +152,97 @@
       }
       return true;
     }
+
+    bool compareNodes(Expression* left, Expression* right) {
+      if (left->_id != right->_id) {
+        return false;
+      }
+
+#define DELEGATE_ID left->_id
+
+// Create cast versions of it for later operations.
+#define DELEGATE_START(id)                                                     \
+  auto* castLeft = left->cast<id>();                                           \
+  WASM_UNUSED(castLeft);                                                       \
+  auto* castRight = right->cast<id>();                                         \
+  WASM_UNUSED(castRight);
+
+// Handle each type of field, comparing it appropriately.
+#define DELEGATE_FIELD_CHILD(id, name)                                         \
+  leftStack.push_back(castLeft->name);                                         \
+  rightStack.push_back(castRight->name);
+
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name)                                  \
+  if (castLeft->name.size() != castRight->name.size()) {                       \
+    return false;                                                              \
+  }                                                                            \
+  for (auto* child : castLeft->name) {                                         \
+    leftStack.push_back(child);                                                \
+  }                                                                            \
+  for (auto* child : castRight->name) {                                        \
+    rightStack.push_back(child);                                               \
+  }
+
+#define COMPARE_FIELD(name)                                                    \
+  if (castLeft->name != castRight->name) {                                     \
+    return false;                                                              \
+  }
+
+#define DELEGATE_FIELD_INT(id, name) COMPARE_FIELD(name)
+#define DELEGATE_FIELD_LITERAL(id, name) COMPARE_FIELD(name)
+#define DELEGATE_FIELD_NAME(id, name) COMPARE_FIELD(name)
+#define DELEGATE_FIELD_SIGNATURE(id, name) COMPARE_FIELD(name)
+#define DELEGATE_FIELD_TYPE(id, name) COMPARE_FIELD(name)
+#define DELEGATE_FIELD_ADDRESS(id, name) COMPARE_FIELD(name)
+
+#define COMPARE_LIST(name)                                                     \
+  if (castLeft->name.size() != castRight->name.size()) {                       \
+    return false;                                                              \
+  }                                                                            \
+  for (Index i = 0; i < castLeft->name.size(); i++) {                          \
+    if (castLeft->name[i] != castRight->name[i]) {                             \
+      return false;                                                            \
+    }                                                                          \
+  }
+
+#define DELEGATE_FIELD_INT_ARRAY(id, name) COMPARE_LIST(name)
+
+#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name)                                \
+  if (castLeft->name.is() != castRight->name.is()) {                           \
+    return false;                                                              \
+  }                                                                            \
+  rightNames[castLeft->name] = castRight->name;
+
+#define DELEGATE_FIELD_SCOPE_NAME_USE(id, name)                                \
+  if (!compareNames(castLeft->name, castRight->name)) {                        \
+    return false;                                                              \
+  }
+
+#define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name)                         \
+  if (castLeft->name.size() != castRight->name.size()) {                       \
+    return false;                                                              \
+  }                                                                            \
+  for (Index i = 0; i < castLeft->name.size(); i++) {                          \
+    if (!compareNames(castLeft->name[i], castRight->name[i])) {                \
+      return false;                                                            \
+    }                                                                          \
+  }
+
+#include "wasm-delegations-fields.h"
+
+      return true;
+    }
+
+    bool compareNames(Name left, Name right) {
+      auto iter = rightNames.find(left);
+      // If it's not found, that means it was defined out of the expression
+      // being compared, in which case we can just treat it literally - it
+      // must be exactly identical.
+      if (iter != rightNames.end()) {
+        left = iter->second;
+      }
+      return left == right;
+    }
   };
 
   return Comparer().compare(left, right, comparer);
@@ -452,12 +258,6 @@
     std::map<Name, Index> internalNames;
     ExpressionStack stack;
 
-    void noteScopeName(Name curr) {
-      if (curr.is()) {
-        internalNames[curr] = internalCounter++;
-      }
-    }
-
     Hasher(Expression* curr) {
       stack.push_back(curr);
 
@@ -465,6 +265,9 @@
         curr = stack.back();
         stack.pop_back();
         if (!curr) {
+          // This was an optional child that was not present. Hash a 0 to
+          // represent that.
+          rehash(digest, 0);
           continue;
         }
         rehash(digest, curr->_id);
@@ -477,27 +280,51 @@
         // call_imports type, etc. The simplest thing is just to hash the
         // type for all of them.
         rehash(digest, curr->type.getID());
-        // Blocks and loops introduce scoping.
-        if (auto* block = curr->dynCast<Block>()) {
-          noteScopeName(block->name);
-        } else if (auto* loop = curr->dynCast<Loop>()) {
-          noteScopeName(loop->name);
-        } else {
-          // For all other nodes, compare their immediate values
-          visitImmediates(curr, *this);
-        }
-        // Hash children
-        Index counter = 0;
-        for (auto* child : ChildIterator(curr)) {
-          stack.push_back(child);
-          counter++;
-        }
-        // Sometimes children are optional, e.g. return, so we must hash
-        // their number as well.
-        rehash(digest, counter);
+        // Hash the contents of the expression.
+        hashExpression(curr);
       }
     }
 
+    void hashExpression(Expression* curr) {
+
+#define DELEGATE_ID curr->_id
+
+// Create cast versions of it for later operations.
+#define DELEGATE_START(id)                                                     \
+  auto* cast = curr->cast<id>();                                               \
+  WASM_UNUSED(cast);
+
+// Handle each type of field, comparing it appropriately.
+#define DELEGATE_GET_FIELD(id, name) cast->name
+
+#define DELEGATE_FIELD_CHILD(id, name) stack.push_back(cast->name);
+
+#define HASH_FIELD(name) rehash(digest, cast->name);
+
+#define DELEGATE_FIELD_INT(id, name) HASH_FIELD(name)
+#define DELEGATE_FIELD_LITERAL(id, name) HASH_FIELD(name)
+#define DELEGATE_FIELD_SIGNATURE(id, name) HASH_FIELD(name)
+
+#define DELEGATE_FIELD_NAME(id, name) visitNonScopeName(cast->name)
+#define DELEGATE_FIELD_TYPE(id, name) visitType(cast->name);
+#define DELEGATE_FIELD_ADDRESS(id, name) visitAddress(cast->name);
+
+// Note that we only note the scope name, but do not also visit it. That means
+// that (block $x) and (block) get the same hash. In other words, we only change
+// the hash based on uses of scope names, that is when there is a noticeable
+// difference in break targets.
+#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name) noteScopeName(cast->name);
+
+#define DELEGATE_FIELD_SCOPE_NAME_USE(id, name) visitScopeName(cast->name);
+
+#include "wasm-delegations-fields.h"
+    }
+
+    void noteScopeName(Name curr) {
+      if (curr.is()) {
+        internalNames[curr] = internalCounter++;
+      }
+    }
     void visitScopeName(Name curr) {
       // Names are relative, we give the same hash for
       // (block $x (br $x))
@@ -508,14 +335,7 @@
       rehash(digest, internalNames[curr]);
     }
     void visitNonScopeName(Name curr) { rehash(digest, uint64_t(curr.str)); }
-    void visitInt(int32_t curr) { rehash(digest, curr); }
-    void visitLiteral(Literal curr) { rehash(digest, curr); }
     void visitType(Type curr) { rehash(digest, curr.getID()); }
-    void visitIndex(Index curr) {
-      static_assert(sizeof(Index) == sizeof(uint32_t),
-                    "wasm64 will need changes here");
-      rehash(digest, curr);
-    }
     void visitAddress(Address curr) { rehash(digest, curr.addr); }
   };
 
diff --git a/binaryen/src/ir/ExpressionManipulator.cpp b/binaryen/src/ir/ExpressionManipulator.cpp
--- a/binaryen/src/ir/ExpressionManipulator.cpp
+++ b/binaryen/src/ir/ExpressionManipulator.cpp
@@ -23,298 +23,92 @@
 
 Expression*
 flexibleCopy(Expression* original, Module& wasm, CustomCopier custom) {
-  struct Copier : public OverriddenVisitor<Copier, Expression*> {
-    Module& wasm;
-    CustomCopier custom;
+  // Perform the copy using a stack of tasks (avoiding recusion).
+  struct CopyTask {
+    // The thing to copy.
+    Expression* original;
+    // The location of the pointer to write the copy to.
+    Expression** destPointer;
+  };
+  std::vector<CopyTask> tasks;
+  Expression* ret;
+  tasks.push_back({original, &ret});
+  while (!tasks.empty()) {
+    auto task = tasks.back();
+    tasks.pop_back();
+    // If the custom copier handled this one, we have nothing to do.
+    auto* copy = custom(task.original);
+    if (copy) {
+      *task.destPointer = copy;
+      continue;
+    }
+    // If the original is a null, just copy that. (This can happen for an
+    // optional child.)
+    auto* original = task.original;
+    if (original == nullptr) {
+      *task.destPointer = nullptr;
+      continue;
+    }
+    // Allocate a new copy, and copy the fields.
 
-    Builder builder;
+#define DELEGATE_ID original->_id
 
-    Copier(Module& wasm, CustomCopier custom)
-      : wasm(wasm), custom(custom), builder(wasm) {}
+// Allocate a new expression of the right type, and create cast versions of it
+// for later operations.
+#define DELEGATE_START(id)                                                     \
+  copy = wasm.allocator.alloc<id>();                                           \
+  auto* castOriginal = original->cast<id>();                                   \
+  WASM_UNUSED(castOriginal);                                                   \
+  auto* castCopy = copy->cast<id>();                                           \
+  WASM_UNUSED(castCopy);
 
-    Expression* copy(Expression* curr) {
-      if (!curr) {
-        return nullptr;
-      }
-      auto* ret = custom(curr);
-      if (ret) {
-        return ret;
-      }
-      return OverriddenVisitor<Copier, Expression*>::visit(curr);
-    }
+// Handle each type of field, copying it appropriately.
+#define DELEGATE_FIELD_CHILD(id, name)                                         \
+  tasks.push_back({castOriginal->name, &castCopy->name});
 
-    Expression* visitBlock(Block* curr) {
-      ExpressionList list(wasm.allocator);
-      for (Index i = 0; i < curr->list.size(); i++) {
-        list.push_back(copy(curr->list[i]));
-      }
-      return builder.makeBlock(curr->name, list, curr->type);
-    }
-    Expression* visitIf(If* curr) {
-      return builder.makeIf(copy(curr->condition),
-                            copy(curr->ifTrue),
-                            copy(curr->ifFalse),
-                            curr->type);
-    }
-    Expression* visitLoop(Loop* curr) {
-      return builder.makeLoop(curr->name, copy(curr->body), curr->type);
-    }
-    Expression* visitBreak(Break* curr) {
-      return builder.makeBreak(
-        curr->name, copy(curr->value), copy(curr->condition));
-    }
-    Expression* visitSwitch(Switch* curr) {
-      return builder.makeSwitch(curr->targets,
-                                curr->default_,
-                                copy(curr->condition),
-                                copy(curr->value));
-    }
-    Expression* visitCall(Call* curr) {
-      auto* ret =
-        builder.makeCall(curr->target, {}, curr->type, curr->isReturn);
-      for (Index i = 0; i < curr->operands.size(); i++) {
-        ret->operands.push_back(copy(curr->operands[i]));
-      }
-      return ret;
-    }
-    Expression* visitCallIndirect(CallIndirect* curr) {
-      std::vector<Expression*> copiedOps;
-      for (auto op : curr->operands) {
-        copiedOps.push_back(copy(op));
-      }
-      return builder.makeCallIndirect(
-        copy(curr->target), copiedOps, curr->sig, curr->isReturn);
-    }
-    Expression* visitLocalGet(LocalGet* curr) {
-      return builder.makeLocalGet(curr->index, curr->type);
-    }
-    Expression* visitLocalSet(LocalSet* curr) {
-      if (curr->isTee()) {
-        return builder.makeLocalTee(curr->index, copy(curr->value), curr->type);
-      } else {
-        return builder.makeLocalSet(curr->index, copy(curr->value));
-      }
-    }
-    Expression* visitGlobalGet(GlobalGet* curr) {
-      return builder.makeGlobalGet(curr->name, curr->type);
-    }
-    Expression* visitGlobalSet(GlobalSet* curr) {
-      return builder.makeGlobalSet(curr->name, copy(curr->value));
-    }
-    Expression* visitLoad(Load* curr) {
-      if (curr->isAtomic) {
-        return builder.makeAtomicLoad(
-          curr->bytes, curr->offset, copy(curr->ptr), curr->type);
-      }
-      return builder.makeLoad(curr->bytes,
-                              LoadUtils::isSignRelevant(curr) ? curr->signed_
-                                                              : false,
-                              curr->offset,
-                              curr->align,
-                              copy(curr->ptr),
-                              curr->type);
-    }
-    Expression* visitStore(Store* curr) {
-      if (curr->isAtomic) {
-        return builder.makeAtomicStore(curr->bytes,
-                                       curr->offset,
-                                       copy(curr->ptr),
-                                       copy(curr->value),
-                                       curr->valueType);
-      }
-      return builder.makeStore(curr->bytes,
-                               curr->offset,
-                               curr->align,
-                               copy(curr->ptr),
-                               copy(curr->value),
-                               curr->valueType);
-    }
-    Expression* visitAtomicRMW(AtomicRMW* curr) {
-      return builder.makeAtomicRMW(curr->op,
-                                   curr->bytes,
-                                   curr->offset,
-                                   copy(curr->ptr),
-                                   copy(curr->value),
-                                   curr->type);
-    }
-    Expression* visitAtomicCmpxchg(AtomicCmpxchg* curr) {
-      return builder.makeAtomicCmpxchg(curr->bytes,
-                                       curr->offset,
-                                       copy(curr->ptr),
-                                       copy(curr->expected),
-                                       copy(curr->replacement),
-                                       curr->type);
-    }
-    Expression* visitAtomicWait(AtomicWait* curr) {
-      return builder.makeAtomicWait(copy(curr->ptr),
-                                    copy(curr->expected),
-                                    copy(curr->timeout),
-                                    curr->expectedType,
-                                    curr->offset);
-    }
-    Expression* visitAtomicNotify(AtomicNotify* curr) {
-      return builder.makeAtomicNotify(
-        copy(curr->ptr), copy(curr->notifyCount), curr->offset);
-    }
-    Expression* visitAtomicFence(AtomicFence* curr) {
-      return builder.makeAtomicFence();
-    }
-    Expression* visitSIMDExtract(SIMDExtract* curr) {
-      return builder.makeSIMDExtract(curr->op, copy(curr->vec), curr->index);
-    }
-    Expression* visitSIMDReplace(SIMDReplace* curr) {
-      return builder.makeSIMDReplace(
-        curr->op, copy(curr->vec), curr->index, copy(curr->value));
-    }
-    Expression* visitSIMDShuffle(SIMDShuffle* curr) {
-      return builder.makeSIMDShuffle(
-        copy(curr->left), copy(curr->right), curr->mask);
-    }
-    Expression* visitSIMDTernary(SIMDTernary* curr) {
-      return builder.makeSIMDTernary(
-        curr->op, copy(curr->a), copy(curr->b), copy(curr->c));
-    }
-    Expression* visitSIMDShift(SIMDShift* curr) {
-      return builder.makeSIMDShift(
-        curr->op, copy(curr->vec), copy(curr->shift));
-    }
-    Expression* visitSIMDLoad(SIMDLoad* curr) {
-      return builder.makeSIMDLoad(
-        curr->op, curr->offset, curr->align, copy(curr->ptr));
-    }
-    Expression* visitConst(Const* curr) {
-      return builder.makeConst(curr->value);
-    }
-    Expression* visitMemoryInit(MemoryInit* curr) {
-      return builder.makeMemoryInit(
-        curr->segment, copy(curr->dest), copy(curr->offset), copy(curr->size));
-    }
-    Expression* visitDataDrop(DataDrop* curr) {
-      return builder.makeDataDrop(curr->segment);
-    }
-    Expression* visitMemoryCopy(MemoryCopy* curr) {
-      return builder.makeMemoryCopy(
-        copy(curr->dest), copy(curr->source), copy(curr->size));
-    }
-    Expression* visitMemoryFill(MemoryFill* curr) {
-      return builder.makeMemoryFill(
-        copy(curr->dest), copy(curr->value), copy(curr->size));
-    }
-    Expression* visitUnary(Unary* curr) {
-      return builder.makeUnary(curr->op, copy(curr->value));
-    }
-    Expression* visitBinary(Binary* curr) {
-      return builder.makeBinary(curr->op, copy(curr->left), copy(curr->right));
-    }
-    Expression* visitSelect(Select* curr) {
-      return builder.makeSelect(copy(curr->condition),
-                                copy(curr->ifTrue),
-                                copy(curr->ifFalse),
-                                curr->type);
-    }
-    Expression* visitDrop(Drop* curr) {
-      return builder.makeDrop(copy(curr->value));
-    }
-    Expression* visitReturn(Return* curr) {
-      return builder.makeReturn(copy(curr->value));
-    }
-    Expression* visitMemorySize(MemorySize* curr) {
-      return builder.makeMemorySize();
-    }
-    Expression* visitMemoryGrow(MemoryGrow* curr) {
-      return builder.makeMemoryGrow(copy(curr->delta));
-    }
-    Expression* visitRefNull(RefNull* curr) {
-      return builder.makeRefNull(curr->type);
-    }
-    Expression* visitRefIsNull(RefIsNull* curr) {
-      return builder.makeRefIsNull(copy(curr->value));
-    }
-    Expression* visitRefFunc(RefFunc* curr) {
-      return builder.makeRefFunc(curr->func);
-    }
-    Expression* visitRefEq(RefEq* curr) {
-      return builder.makeRefEq(copy(curr->left), copy(curr->right));
-    }
-    Expression* visitTry(Try* curr) {
-      return builder.makeTry(
-        copy(curr->body), copy(curr->catchBody), curr->type);
-    }
-    Expression* visitThrow(Throw* curr) {
-      std::vector<Expression*> operands;
-      for (Index i = 0; i < curr->operands.size(); i++) {
-        operands.push_back(copy(curr->operands[i]));
-      }
-      return builder.makeThrow(curr->event, std::move(operands));
-    }
-    Expression* visitRethrow(Rethrow* curr) {
-      return builder.makeRethrow(copy(curr->exnref));
-    }
-    Expression* visitBrOnExn(BrOnExn* curr) {
-      return builder.makeBrOnExn(
-        curr->name, curr->event, copy(curr->exnref), curr->sent);
-    }
-    Expression* visitNop(Nop* curr) { return builder.makeNop(); }
-    Expression* visitUnreachable(Unreachable* curr) {
-      return builder.makeUnreachable();
-    }
-    Expression* visitPop(Pop* curr) { return builder.makePop(curr->type); }
-    Expression* visitTupleMake(TupleMake* curr) {
-      std::vector<Expression*> operands;
-      for (auto* op : curr->operands) {
-        operands.push_back(copy(op));
-      }
-      return builder.makeTupleMake(std::move(operands));
-    }
-    Expression* visitTupleExtract(TupleExtract* curr) {
-      return builder.makeTupleExtract(copy(curr->tuple), curr->index);
-    }
-    Expression* visitI31New(I31New* curr) {
-      return builder.makeI31New(copy(curr->value));
-    }
-    Expression* visitI31Get(I31Get* curr) {
-      return builder.makeI31Get(copy(curr->i31), curr->signed_);
-    }
-    Expression* visitRefTest(RefTest* curr) {
-      WASM_UNREACHABLE("TODO (gc): ref.test");
-    }
-    Expression* visitRefCast(RefCast* curr) {
-      WASM_UNREACHABLE("TODO (gc): ref.cast");
-    }
-    Expression* visitBrOnCast(BrOnCast* curr) {
-      WASM_UNREACHABLE("TODO (gc): br_on_cast");
-    }
-    Expression* visitRttCanon(RttCanon* curr) {
-      WASM_UNREACHABLE("TODO (gc): rtt.canon");
-    }
-    Expression* visitRttSub(RttSub* curr) {
-      WASM_UNREACHABLE("TODO (gc): rtt.sub");
-    }
-    Expression* visitStructNew(StructNew* curr) {
-      WASM_UNREACHABLE("TODO (gc): struct.new");
-    }
-    Expression* visitStructGet(StructGet* curr) {
-      WASM_UNREACHABLE("TODO (gc): struct.get");
-    }
-    Expression* visitStructSet(StructSet* curr) {
-      WASM_UNREACHABLE("TODO (gc): struct.set");
-    }
-    Expression* visitArrayNew(ArrayNew* curr) {
-      WASM_UNREACHABLE("TODO (gc): array.new");
-    }
-    Expression* visitArrayGet(ArrayGet* curr) {
-      WASM_UNREACHABLE("TODO (gc): array.get");
-    }
-    Expression* visitArraySet(ArraySet* curr) {
-      WASM_UNREACHABLE("TODO (gc): array.set");
-    }
-    Expression* visitArrayLen(ArrayLen* curr) {
-      WASM_UNREACHABLE("TODO (gc): array.len");
-    }
-  };
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name)                                  \
+  castCopy->name.resize(castOriginal->name.size());                            \
+  for (Index i = 0; i < castOriginal->name.size(); i++) {                      \
+    tasks.push_back({castOriginal->name[i], &castCopy->name[i]});              \
+  }
 
-  Copier copier(wasm, custom);
-  return copier.copy(original);
+#define COPY_FIELD(name) castCopy->name = castOriginal->name;
+
+#define DELEGATE_FIELD_INT(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_LITERAL(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_NAME(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_SCOPE_NAME_USE(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_SIGNATURE(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_TYPE(id, name) COPY_FIELD(name)
+#define DELEGATE_FIELD_ADDRESS(id, name) COPY_FIELD(name)
+
+#define COPY_FIELD_LIST(name)                                                  \
+  for (Index i = 0; i < castOriginal->name.size(); i++) {                      \
+    castCopy->name[i] = castOriginal->name[i];                                 \
+  }
+
+#define COPY_VECTOR(name)                                                      \
+  castCopy->name.resize(castOriginal->name.size());                            \
+  COPY_FIELD_LIST(name)
+
+#define COPY_ARRAY(name)                                                       \
+  assert(castCopy->name.size() == castOriginal->name.size());                  \
+  COPY_FIELD_LIST(name)
+
+#define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name) COPY_VECTOR(name)
+
+#define DELEGATE_FIELD_INT_ARRAY(id, name) COPY_ARRAY(name)
+
+#include "wasm-delegations-fields.h"
+
+    // The type can be simply copied.
+    copy->type = original->type;
+
+    // Write the copy to where it should be referred to.
+    *task.destPointer = copy;
+  }
+  return ret;
 }
 
 // Splice an item into the middle of a block's list
diff --git a/binaryen/src/ir/LocalGraph.cpp b/binaryen/src/ir/LocalGraph.cpp
--- a/binaryen/src/ir/LocalGraph.cpp
+++ b/binaryen/src/ir/LocalGraph.cpp
@@ -20,7 +20,6 @@
 #include <ir/find_all.h>
 #include <ir/local-graph.h>
 #include <wasm-builder.h>
-#include <wasm-printing.h>
 
 namespace wasm {
 
diff --git a/binaryen/src/ir/ReFinalize.cpp b/binaryen/src/ir/ReFinalize.cpp
--- a/binaryen/src/ir/ReFinalize.cpp
+++ b/binaryen/src/ir/ReFinalize.cpp
@@ -109,6 +109,10 @@
 void ReFinalize::visitSIMDTernary(SIMDTernary* curr) { curr->finalize(); }
 void ReFinalize::visitSIMDShift(SIMDShift* curr) { curr->finalize(); }
 void ReFinalize::visitSIMDLoad(SIMDLoad* curr) { curr->finalize(); }
+void ReFinalize::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+  curr->finalize();
+}
+void ReFinalize::visitPrefetch(Prefetch* curr) { curr->finalize(); }
 void ReFinalize::visitMemoryInit(MemoryInit* curr) { curr->finalize(); }
 void ReFinalize::visitDataDrop(DataDrop* curr) { curr->finalize(); }
 void ReFinalize::visitMemoryCopy(MemoryCopy* curr) { curr->finalize(); }
@@ -123,7 +127,11 @@
 void ReFinalize::visitMemoryGrow(MemoryGrow* curr) { curr->finalize(); }
 void ReFinalize::visitRefNull(RefNull* curr) { curr->finalize(); }
 void ReFinalize::visitRefIsNull(RefIsNull* curr) { curr->finalize(); }
-void ReFinalize::visitRefFunc(RefFunc* curr) { curr->finalize(); }
+void ReFinalize::visitRefFunc(RefFunc* curr) {
+  // TODO: should we look up the function and update the type from there? This
+  // could handle a change to the function's type, but is also not really what
+  // this class has been meant to do.
+}
 void ReFinalize::visitRefEq(RefEq* curr) { curr->finalize(); }
 void ReFinalize::visitTry(Try* curr) { curr->finalize(); }
 void ReFinalize::visitThrow(Throw* curr) { curr->finalize(); }
@@ -143,11 +151,16 @@
 void ReFinalize::visitTupleExtract(TupleExtract* curr) { curr->finalize(); }
 void ReFinalize::visitI31New(I31New* curr) { curr->finalize(); }
 void ReFinalize::visitI31Get(I31Get* curr) { curr->finalize(); }
+void ReFinalize::visitCallRef(CallRef* curr) { curr->finalize(); }
 void ReFinalize::visitRefTest(RefTest* curr) { curr->finalize(); }
 void ReFinalize::visitRefCast(RefCast* curr) { curr->finalize(); }
 void ReFinalize::visitBrOnCast(BrOnCast* curr) {
   curr->finalize();
-  WASM_UNREACHABLE("TODO (gc): br_on_cast");
+  if (curr->type == Type::unreachable) {
+    replaceUntaken(curr->ref, nullptr);
+  } else {
+    updateBreakValueType(curr->name, curr->getCastType());
+  }
 }
 void ReFinalize::visitRttCanon(RttCanon* curr) { curr->finalize(); }
 void ReFinalize::visitRttSub(RttSub* curr) { curr->finalize(); }
diff --git a/binaryen/src/ir/abstract.h b/binaryen/src/ir/abstract.h
--- a/binaryen/src/ir/abstract.h
+++ b/binaryen/src/ir/abstract.h
@@ -27,6 +27,7 @@
 
 enum Op {
   // Unary
+  Abs,
   Neg,
   // Binary
   Add,
@@ -91,6 +92,8 @@
     }
     case Type::f32: {
       switch (op) {
+        case Abs:
+          return AbsFloat32;
         case Neg:
           return NegFloat32;
         default:
@@ -100,6 +103,8 @@
     }
     case Type::f64: {
       switch (op) {
+        case Abs:
+          return AbsFloat64;
         case Neg:
           return NegFloat64;
         default:
diff --git a/binaryen/src/ir/branch-utils.h b/binaryen/src/ir/branch-utils.h
--- a/binaryen/src/ir/branch-utils.h
+++ b/binaryen/src/ir/branch-utils.h
@@ -28,111 +28,127 @@
 // Some branches are obviously not actually reachable (e.g. (br $out
 // (unreachable)))
 
-inline bool isBranchReachable(Break* br) {
-  return !(br->value && br->value->type == Type::unreachable) &&
-         !(br->condition && br->condition->type == Type::unreachable);
+inline bool isBranchReachable(Expression* expr) {
+  // If any child is unreachable, the branch is not taken. Note that expr itself
+  // may be unreachable regardless (as in the case of a simple Break with no
+  // condition, which is still taken).
+  for (auto child : ChildIterator(expr)) {
+    if (child->type == Type::unreachable) {
+      return false;
+    }
+  }
+  return true;
 }
 
-inline bool isBranchReachable(Switch* sw) {
-  return !(sw->value && sw->value->type == Type::unreachable) &&
-         sw->condition->type != Type::unreachable;
-}
+// Perform a generic operation on uses of scope names (branch targets) in an
+// expression. The provided function receives a Name& which it can modify if it
+// needs to.
+template<typename T> void operateOnScopeNameUses(Expression* expr, T func) {
+#define DELEGATE_ID expr->_id
 
-inline bool isBranchReachable(BrOnExn* br) {
-  return br->exnref->type != Type::unreachable;
+#define DELEGATE_START(id)                                                     \
+  auto* cast = expr->cast<id>();                                               \
+  WASM_UNUSED(cast);
+
+#define DELEGATE_GET_FIELD(id, name) cast->name
+
+#define DELEGATE_FIELD_SCOPE_NAME_USE(id, name) func(cast->name);
+
+#define DELEGATE_FIELD_CHILD(id, name)
+#define DELEGATE_FIELD_INT(id, name)
+#define DELEGATE_FIELD_LITERAL(id, name)
+#define DELEGATE_FIELD_NAME(id, name)
+#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name)
+#define DELEGATE_FIELD_SIGNATURE(id, name)
+#define DELEGATE_FIELD_TYPE(id, name)
+#define DELEGATE_FIELD_ADDRESS(id, name)
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name)
+#define DELEGATE_FIELD_INT_ARRAY(id, name)
+
+#include "wasm-delegations-fields.h"
 }
 
-inline bool isBranchReachable(Expression* expr) {
-  if (auto* br = expr->dynCast<Break>()) {
-    return isBranchReachable(br);
-  } else if (auto* sw = expr->dynCast<Switch>()) {
-    return isBranchReachable(sw);
-  } else if (auto* br = expr->dynCast<BrOnExn>()) {
-    return isBranchReachable(br);
-  }
-  WASM_UNREACHABLE("unexpected expression type");
+// Similar to operateOnScopeNameUses, but also passes in the type that is sent
+// if the branch is taken. The type is none if there is no value.
+template<typename T>
+void operateOnScopeNameUsesAndSentTypes(Expression* expr, T func) {
+  operateOnScopeNameUses(expr, [&](Name& name) {
+    // There isn't a delegate mechanism for getting a sent value, so do a direct
+    // if-else chain. This will need to be updated with new br variants.
+    if (auto* br = expr->dynCast<Break>()) {
+      func(name, br->value ? br->value->type : Type::none);
+    } else if (auto* sw = expr->dynCast<Switch>()) {
+      func(name, sw->value ? sw->value->type : Type::none);
+    } else if (auto* br = expr->dynCast<BrOnExn>()) {
+      func(name, br->sent);
+    } else if (auto* br = expr->dynCast<BrOnCast>()) {
+      func(name, br->getCastType());
+    } else {
+      WASM_UNREACHABLE("bad br type");
+    }
+  });
 }
 
-using NameSet = std::set<Name>;
+// Perform a generic operation on definitions of scope names in an expression.
+// The provided function receives a Name& which it can modify if it needs to.
+template<typename T> void operateOnScopeNameDefs(Expression* expr, T func) {
+#define DELEGATE_ID expr->_id
 
-inline NameSet getUniqueTargets(Break* br) { return {br->name}; }
+#define DELEGATE_START(id)                                                     \
+  auto* cast = expr->cast<id>();                                               \
+  WASM_UNUSED(cast);
 
-inline NameSet getUniqueTargets(Switch* sw) {
-  NameSet ret;
-  for (auto target : sw->targets) {
-    ret.insert(target);
-  }
-  ret.insert(sw->default_);
-  return ret;
+#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name) func(cast->name)
+
+#define DELEGATE_FIELD_CHILD(id, name)
+#define DELEGATE_FIELD_INT(id, name)
+#define DELEGATE_FIELD_LITERAL(id, name)
+#define DELEGATE_FIELD_NAME(id, name)
+#define DELEGATE_FIELD_SIGNATURE(id, name)
+#define DELEGATE_FIELD_TYPE(id, name)
+#define DELEGATE_FIELD_ADDRESS(id, name)
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name)
+#define DELEGATE_FIELD_INT_ARRAY(id, name)
+#define DELEGATE_FIELD_SCOPE_NAME_USE(id, name)
+#define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name)
+
+#include "wasm-delegations-fields.h"
 }
 
-inline NameSet getUniqueTargets(BrOnExn* br) { return {br->name}; }
+using NameSet = std::set<Name>;
 
 inline NameSet getUniqueTargets(Expression* expr) {
-  if (auto* br = expr->dynCast<Break>()) {
-    return getUniqueTargets(br);
-  }
-  if (auto* br = expr->dynCast<Switch>()) {
-    return getUniqueTargets(br);
-  }
-  if (auto* br = expr->dynCast<BrOnExn>()) {
-    return getUniqueTargets(br);
-  }
-  return {};
+  NameSet ret;
+  operateOnScopeNameUses(expr, [&](Name& name) { ret.insert(name); });
+  return ret;
 }
+
 // If we branch to 'from', change that to 'to' instead.
 inline bool replacePossibleTarget(Expression* branch, Name from, Name to) {
   bool worked = false;
-  if (auto* br = branch->dynCast<Break>()) {
-    if (br->name == from) {
-      br->name = to;
-      worked = true;
-    }
-  } else if (auto* sw = branch->dynCast<Switch>()) {
-    for (auto& target : sw->targets) {
-      if (target == from) {
-        target = to;
-        worked = true;
-      }
-    }
-    if (sw->default_ == from) {
-      sw->default_ = to;
-      worked = true;
-    }
-  } else if (auto* br = branch->dynCast<BrOnExn>()) {
-    if (br->name == from) {
-      br->name = to;
+  operateOnScopeNameUses(branch, [&](Name& name) {
+    if (name == from) {
+      name = to;
       worked = true;
     }
-  } else {
-    WASM_UNREACHABLE("unexpected expression type");
-  }
+  });
   return worked;
 }
 
-// returns the set of targets to which we branch that are
-// outside of a node
+// Returns the set of targets to which we branch that are
+// outside of an expression.
 inline NameSet getExitingBranches(Expression* ast) {
-  struct Scanner : public PostWalker<Scanner> {
+  struct Scanner
+    : public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
     NameSet targets;
 
-    void visitBreak(Break* curr) { targets.insert(curr->name); }
-    void visitSwitch(Switch* curr) {
-      for (auto target : curr->targets) {
-        targets.insert(target);
-      }
-      targets.insert(curr->default_);
-    }
-    void visitBrOnExn(BrOnExn* curr) { targets.insert(curr->name); }
-    void visitBlock(Block* curr) {
-      if (curr->name.is()) {
-        targets.erase(curr->name);
-      }
-    }
-    void visitLoop(Loop* curr) {
-      if (curr->name.is()) {
-        targets.erase(curr->name);
-      }
+    void visitExpression(Expression* curr) {
+      operateOnScopeNameDefs(curr, [&](Name& name) {
+        if (name.is()) {
+          targets.erase(name);
+        }
+      });
+      operateOnScopeNameUses(curr, [&](Name& name) { targets.insert(name); });
     }
   };
   Scanner scanner;
@@ -144,18 +160,16 @@
 // returns the list of all branch targets in a node
 
 inline NameSet getBranchTargets(Expression* ast) {
-  struct Scanner : public PostWalker<Scanner> {
+  struct Scanner
+    : public PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>> {
     NameSet targets;
 
-    void visitBlock(Block* curr) {
-      if (curr->name.is()) {
-        targets.insert(curr->name);
-      }
-    }
-    void visitLoop(Loop* curr) {
-      if (curr->name.is()) {
-        targets.insert(curr->name);
-      }
+    void visitExpression(Expression* curr) {
+      operateOnScopeNameDefs(curr, [&](Name& name) {
+        if (name.is()) {
+          targets.insert(name);
+        }
+      });
     }
   };
   Scanner scanner;
@@ -166,52 +180,33 @@
 // Finds if there are branches targeting a name. Note that since names are
 // unique in our IR, we just need to look for the name, and do not need
 // to analyze scoping.
-struct BranchSeeker : public PostWalker<BranchSeeker> {
+struct BranchSeeker
+  : public PostWalker<BranchSeeker, UnifiedExpressionVisitor<BranchSeeker>> {
   Name target;
 
   Index found = 0;
-  Type valueType;
+  // None indicates no value is sent.
+  Type valueType = Type::none;
 
   BranchSeeker(Name target) : target(target) {}
 
-  void noteFound(Expression* value) {
-    noteFound(value ? value->type : Type::none);
-  }
-
-  void noteFound(Type type) {
+  void noteFound(Type newType) {
     found++;
-    if (found == 1) {
-      valueType = Type::unreachable;
-    }
-    if (type != Type::unreachable) {
-      valueType = type;
-    }
-  }
-
-  void visitBreak(Break* curr) {
-    // check the break
-    if (curr->name == target) {
-      noteFound(curr->value);
+    if (newType != Type::none) {
+      if (found == 1) {
+        valueType = newType;
+      } else {
+        valueType = Type::getLeastUpperBound(valueType, newType);
+      }
     }
   }
 
-  void visitSwitch(Switch* curr) {
-    // check the switch
-    for (auto name : curr->targets) {
+  void visitExpression(Expression* curr) {
+    operateOnScopeNameUsesAndSentTypes(curr, [&](Name& name, Type type) {
       if (name == target) {
-        noteFound(curr->value);
+        noteFound(type);
       }
-    }
-    if (curr->default_ == target) {
-      noteFound(curr->value);
-    }
-  }
-
-  void visitBrOnExn(BrOnExn* curr) {
-    // check the br_on_exn
-    if (curr->name == target) {
-      noteFound(curr->sent);
-    }
+    });
   }
 
   static bool has(Expression* tree, Name target) {
diff --git a/binaryen/src/ir/cost.h b/binaryen/src/ir/cost.h
--- a/binaryen/src/ir/cost.h
+++ b/binaryen/src/ir/cost.h
@@ -24,7 +24,7 @@
 
 // Measure the execution cost of an AST. Very handwave-ey
 
-struct CostAnalyzer : public Visitor<CostAnalyzer, Index> {
+struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, Index> {
   CostAnalyzer(Expression* ast) { cost = visit(ast); }
 
   Index cost;
@@ -65,18 +65,38 @@
     }
     return ret;
   }
+  Index visitCallRef(CallRef* curr) {
+    Index ret = 5 + visit(curr->target);
+    for (auto* child : curr->operands) {
+      ret += visit(child);
+    }
+    return ret;
+  }
   Index visitLocalGet(LocalGet* curr) { return 0; }
-  Index visitLocalSet(LocalSet* curr) { return 1; }
+  Index visitLocalSet(LocalSet* curr) { return 1 + visit(curr->value); }
   Index visitGlobalGet(GlobalGet* curr) { return 1; }
-  Index visitGlobalSet(GlobalSet* curr) { return 2; }
+  Index visitGlobalSet(GlobalSet* curr) { return 2 + visit(curr->value); }
   Index visitLoad(Load* curr) {
     return 1 + visit(curr->ptr) + 10 * curr->isAtomic;
   }
   Index visitStore(Store* curr) {
     return 2 + visit(curr->ptr) + visit(curr->value) + 10 * curr->isAtomic;
   }
-  Index visitAtomicRMW(AtomicRMW* curr) { return 100; }
-  Index visitAtomicCmpxchg(AtomicCmpxchg* curr) { return 100; }
+  Index visitAtomicRMW(AtomicRMW* curr) {
+    return 100 + visit(curr->ptr) + visit(curr->value);
+  }
+  Index visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+    return 100 + visit(curr->ptr) + visit(curr->expected) +
+           visit(curr->replacement);
+  }
+  Index visitAtomicWait(AtomicWait* curr) {
+    return 100 + visit(curr->ptr) + visit(curr->expected) +
+           visit(curr->timeout);
+  }
+  Index visitAtomicNotify(AtomicNotify* curr) {
+    return 100 + visit(curr->ptr) + visit(curr->notifyCount);
+  }
+  Index visitAtomicFence(AtomicFence* curr) { return 100; }
   Index visitConst(Const* curr) { return 1; }
   Index visitUnary(Unary* curr) {
     Index ret = 0;
@@ -157,6 +177,7 @@
       case AnyTrueVecI8x16:
       case AllTrueVecI8x16:
       case BitmaskVecI8x16:
+      case PopcntVecI8x16:
       case AbsVecI16x8:
       case NegVecI16x8:
       case AnyTrueVecI16x8:
@@ -168,8 +189,7 @@
       case AllTrueVecI32x4:
       case BitmaskVecI32x4:
       case NegVecI64x2:
-      case AnyTrueVecI64x2:
-      case AllTrueVecI64x2:
+      case BitmaskVecI64x2:
       case AbsVecF32x4:
       case NegVecF32x4:
       case SqrtVecF32x4:
@@ -184,6 +204,10 @@
       case FloorVecF64x2:
       case TruncVecF64x2:
       case NearestVecF64x2:
+      case ExtAddPairwiseSVecI8x16ToI16x8:
+      case ExtAddPairwiseUVecI8x16ToI16x8:
+      case ExtAddPairwiseSVecI16x8ToI32x4:
+      case ExtAddPairwiseUVecI16x8ToI32x4:
       case TruncSatSVecF32x4ToVecI32x4:
       case TruncSatUVecF32x4ToVecI32x4:
       case TruncSatSVecF64x2ToVecI64x2:
@@ -200,7 +224,12 @@
       case WidenHighSVecI16x8ToVecI32x4:
       case WidenLowUVecI16x8ToVecI32x4:
       case WidenHighUVecI16x8ToVecI32x4:
-        return 1;
+      case WidenLowSVecI32x4ToVecI64x2:
+      case WidenHighSVecI32x4ToVecI64x2:
+      case WidenLowUVecI32x4ToVecI64x2:
+      case WidenHighUVecI32x4ToVecI64x2:
+        ret = 1;
+        break;
       case InvalidUnary:
         WASM_UNREACHABLE("invalid unary op");
     }
@@ -210,8 +239,6 @@
     Index ret = 0;
     switch (curr->op) {
       case AddInt32:
-        ret = 1;
-        break;
       case SubInt32:
         ret = 1;
         break;
@@ -219,44 +246,20 @@
         ret = 2;
         break;
       case DivSInt32:
-        ret = 3;
-        break;
       case DivUInt32:
-        ret = 3;
-        break;
       case RemSInt32:
-        ret = 3;
-        break;
       case RemUInt32:
         ret = 3;
         break;
       case AndInt32:
-        ret = 1;
-        break;
       case OrInt32:
-        ret = 1;
-        break;
       case XorInt32:
-        ret = 1;
-        break;
       case ShlInt32:
-        ret = 1;
-        break;
       case ShrUInt32:
-        ret = 1;
-        break;
       case ShrSInt32:
-        ret = 1;
-        break;
       case RotLInt32:
-        ret = 1;
-        break;
       case RotRInt32:
-        ret = 1;
-        break;
       case AddInt64:
-        ret = 1;
-        break;
       case SubInt64:
         ret = 1;
         break;
@@ -264,44 +267,22 @@
         ret = 2;
         break;
       case DivSInt64:
-        ret = 3;
-        break;
       case DivUInt64:
-        ret = 3;
-        break;
       case RemSInt64:
-        ret = 3;
-        break;
       case RemUInt64:
         ret = 3;
         break;
       case AndInt64:
-        ret = 1;
-        break;
       case OrInt64:
-        ret = 1;
-        break;
       case XorInt64:
         ret = 1;
         break;
       case ShlInt64:
-        ret = 1;
-        break;
       case ShrUInt64:
-        ret = 1;
-        break;
       case ShrSInt64:
-        ret = 1;
-        break;
       case RotLInt64:
-        ret = 1;
-        break;
       case RotRInt64:
-        ret = 1;
-        break;
       case AddFloat32:
-        ret = 1;
-        break;
       case SubFloat32:
         ret = 1;
         break;
@@ -312,17 +293,9 @@
         ret = 3;
         break;
       case CopySignFloat32:
-        ret = 1;
-        break;
       case MinFloat32:
-        ret = 1;
-        break;
       case MaxFloat32:
-        ret = 1;
-        break;
       case AddFloat64:
-        ret = 1;
-        break;
       case SubFloat64:
         ret = 1;
         break;
@@ -333,263 +306,92 @@
         ret = 3;
         break;
       case CopySignFloat64:
-        ret = 1;
-        break;
       case MinFloat64:
-        ret = 1;
-        break;
       case MaxFloat64:
-        ret = 1;
-        break;
+      case EqInt32:
+      case NeInt32:
       case LtUInt32:
-        ret = 1;
-        break;
       case LtSInt32:
-        ret = 1;
-        break;
       case LeUInt32:
-        ret = 1;
-        break;
       case LeSInt32:
-        ret = 1;
-        break;
       case GtUInt32:
-        ret = 1;
-        break;
       case GtSInt32:
-        ret = 1;
-        break;
       case GeUInt32:
-        ret = 1;
-        break;
       case GeSInt32:
-        ret = 1;
-        break;
+      case EqInt64:
+      case NeInt64:
       case LtUInt64:
-        ret = 1;
-        break;
       case LtSInt64:
-        ret = 1;
-        break;
       case LeUInt64:
-        ret = 1;
-        break;
       case LeSInt64:
-        ret = 1;
-        break;
       case GtUInt64:
-        ret = 1;
-        break;
       case GtSInt64:
-        ret = 1;
-        break;
       case GeUInt64:
-        ret = 1;
-        break;
       case GeSInt64:
-        ret = 1;
-        break;
+      case EqFloat32:
+      case NeFloat32:
       case LtFloat32:
-        ret = 1;
-        break;
       case GtFloat32:
-        ret = 1;
-        break;
       case LeFloat32:
-        ret = 1;
-        break;
       case GeFloat32:
-        ret = 1;
-        break;
+      case EqFloat64:
+      case NeFloat64:
       case LtFloat64:
-        ret = 1;
-        break;
       case GtFloat64:
-        ret = 1;
-        break;
       case LeFloat64:
-        ret = 1;
-        break;
       case GeFloat64:
-        ret = 1;
-        break;
-      case EqInt32:
-        ret = 1;
-        break;
-      case NeInt32:
-        ret = 1;
-        break;
-      case EqInt64:
-        ret = 1;
-        break;
-      case NeInt64:
-        ret = 1;
-        break;
-      case EqFloat32:
-        ret = 1;
-        break;
-      case NeFloat32:
-        ret = 1;
-        break;
-      case EqFloat64:
-        ret = 1;
-        break;
-      case NeFloat64:
-        ret = 1;
-        break;
       case EqVecI8x16:
-        ret = 1;
-        break;
       case NeVecI8x16:
-        ret = 1;
-        break;
       case LtSVecI8x16:
-        ret = 1;
-        break;
       case LtUVecI8x16:
-        ret = 1;
-        break;
       case LeSVecI8x16:
-        ret = 1;
-        break;
       case LeUVecI8x16:
-        ret = 1;
-        break;
       case GtSVecI8x16:
-        ret = 1;
-        break;
       case GtUVecI8x16:
-        ret = 1;
-        break;
       case GeSVecI8x16:
-        ret = 1;
-        break;
       case GeUVecI8x16:
-        ret = 1;
-        break;
       case EqVecI16x8:
-        ret = 1;
-        break;
       case NeVecI16x8:
-        ret = 1;
-        break;
       case LtSVecI16x8:
-        ret = 1;
-        break;
       case LtUVecI16x8:
-        ret = 1;
-        break;
       case LeSVecI16x8:
-        ret = 1;
-        break;
       case LeUVecI16x8:
-        ret = 1;
-        break;
       case GtSVecI16x8:
-        ret = 1;
-        break;
       case GtUVecI16x8:
-        ret = 1;
-        break;
       case GeSVecI16x8:
-        ret = 1;
-        break;
       case GeUVecI16x8:
-        ret = 1;
-        break;
       case EqVecI32x4:
-        ret = 1;
-        break;
       case NeVecI32x4:
-        ret = 1;
-        break;
       case LtSVecI32x4:
-        ret = 1;
-        break;
       case LtUVecI32x4:
-        ret = 1;
-        break;
       case LeSVecI32x4:
-        ret = 1;
-        break;
       case LeUVecI32x4:
-        ret = 1;
-        break;
       case GtSVecI32x4:
-        ret = 1;
-        break;
       case GtUVecI32x4:
-        ret = 1;
-        break;
       case GeSVecI32x4:
-        ret = 1;
-        break;
       case GeUVecI32x4:
-        ret = 1;
-        break;
+      case EqVecI64x2:
       case EqVecF32x4:
-        ret = 1;
-        break;
       case NeVecF32x4:
-        ret = 1;
-        break;
       case LtVecF32x4:
-        ret = 1;
-        break;
       case LeVecF32x4:
-        ret = 1;
-        break;
       case GtVecF32x4:
-        ret = 1;
-        break;
       case GeVecF32x4:
-        ret = 1;
-        break;
       case EqVecF64x2:
-        ret = 1;
-        break;
       case NeVecF64x2:
-        ret = 1;
-        break;
       case LtVecF64x2:
-        ret = 1;
-        break;
       case LeVecF64x2:
-        ret = 1;
-        break;
       case GtVecF64x2:
-        ret = 1;
-        break;
       case GeVecF64x2:
-        ret = 1;
-        break;
       case AndVec128:
-        ret = 1;
-        break;
       case OrVec128:
-        ret = 1;
-        break;
       case XorVec128:
-        ret = 1;
-        break;
       case AndNotVec128:
-        ret = 1;
-        break;
       case AddVecI8x16:
-        ret = 1;
-        break;
       case AddSatSVecI8x16:
-        ret = 1;
-        break;
       case AddSatUVecI8x16:
-        ret = 1;
-        break;
       case SubVecI8x16:
-        ret = 1;
-        break;
       case SubSatSVecI8x16:
-        ret = 1;
-        break;
       case SubSatUVecI8x16:
         ret = 1;
         break;
@@ -597,35 +399,15 @@
         ret = 2;
         break;
       case MinSVecI8x16:
-        ret = 1;
-        break;
       case MinUVecI8x16:
-        ret = 1;
-        break;
       case MaxSVecI8x16:
-        ret = 1;
-        break;
       case MaxUVecI8x16:
-        ret = 1;
-        break;
       case AvgrUVecI8x16:
-        ret = 1;
-        break;
       case AddVecI16x8:
-        ret = 1;
-        break;
       case AddSatSVecI16x8:
-        ret = 1;
-        break;
       case AddSatUVecI16x8:
-        ret = 1;
-        break;
       case SubVecI16x8:
-        ret = 1;
-        break;
       case SubSatSVecI16x8:
-        ret = 1;
-        break;
       case SubSatUVecI16x8:
         ret = 1;
         break;
@@ -633,23 +415,16 @@
         ret = 2;
         break;
       case MinSVecI16x8:
-        ret = 1;
-        break;
       case MinUVecI16x8:
-        ret = 1;
-        break;
       case MaxSVecI16x8:
-        ret = 1;
-        break;
       case MaxUVecI16x8:
-        ret = 1;
-        break;
       case AvgrUVecI16x8:
-        ret = 1;
-        break;
+      case Q15MulrSatSVecI16x8:
+      case ExtMulLowSVecI16x8:
+      case ExtMulHighSVecI16x8:
+      case ExtMulLowUVecI16x8:
+      case ExtMulHighUVecI16x8:
       case AddVecI32x4:
-        ret = 1;
-        break;
       case SubVecI32x4:
         ret = 1;
         break;
@@ -657,32 +432,22 @@
         ret = 2;
         break;
       case MinSVecI32x4:
-        ret = 1;
-        break;
       case MinUVecI32x4:
-        ret = 1;
-        break;
       case MaxSVecI32x4:
-        ret = 1;
-        break;
       case MaxUVecI32x4:
-        ret = 1;
-        break;
       case DotSVecI16x8ToVecI32x4:
-        ret = 1;
-        break;
+      case ExtMulLowSVecI32x4:
+      case ExtMulHighSVecI32x4:
+      case ExtMulLowUVecI32x4:
+      case ExtMulHighUVecI32x4:
       case AddVecI64x2:
-        ret = 1;
-        break;
       case SubVecI64x2:
-        ret = 1;
-        break;
       case MulVecI64x2:
-        ret = 1;
-        break;
+      case ExtMulLowSVecI64x2:
+      case ExtMulHighSVecI64x2:
+      case ExtMulLowUVecI64x2:
+      case ExtMulHighUVecI64x2:
       case AddVecF32x4:
-        ret = 1;
-        break;
       case SubVecF32x4:
         ret = 1;
         break;
@@ -693,20 +458,10 @@
         ret = 3;
         break;
       case MinVecF32x4:
-        ret = 1;
-        break;
       case MaxVecF32x4:
-        ret = 1;
-        break;
       case PMinVecF32x4:
-        ret = 1;
-        break;
       case PMaxVecF32x4:
-        ret = 1;
-        break;
       case AddVecF64x2:
-        ret = 1;
-        break;
       case SubVecF64x2:
         ret = 1;
         break;
@@ -717,29 +472,13 @@
         ret = 3;
         break;
       case MinVecF64x2:
-        ret = 1;
-        break;
       case MaxVecF64x2:
-        ret = 1;
-        break;
       case PMinVecF64x2:
-        ret = 1;
-        break;
       case PMaxVecF64x2:
-        ret = 1;
-        break;
       case NarrowSVecI16x8ToVecI8x16:
-        ret = 1;
-        break;
       case NarrowUVecI16x8ToVecI8x16:
-        ret = 1;
-        break;
       case NarrowSVecI32x4ToVecI16x8:
-        ret = 1;
-        break;
       case NarrowUVecI32x4ToVecI16x8:
-        ret = 1;
-        break;
       case SwizzleVec8x16:
         ret = 1;
         break;
@@ -749,13 +488,56 @@
     return ret + visit(curr->left) + visit(curr->right);
   }
   Index visitSelect(Select* curr) {
-    return 2 + visit(curr->condition) + visit(curr->ifTrue) +
+    return 1 + visit(curr->condition) + visit(curr->ifTrue) +
            visit(curr->ifFalse);
   }
   Index visitDrop(Drop* curr) { return visit(curr->value); }
   Index visitReturn(Return* curr) { return maybeVisit(curr->value); }
   Index visitMemorySize(MemorySize* curr) { return 1; }
-  Index visitMemoryGrow(MemoryGrow* curr) { return 100; }
+  Index visitMemoryGrow(MemoryGrow* curr) { return 100 + visit(curr->delta); }
+  Index visitMemoryInit(MemoryInit* curr) {
+    return 6 + visit(curr->dest) + visit(curr->offset) + visit(curr->size);
+  }
+  Index visitMemoryCopy(MemoryCopy* curr) {
+    return 6 + visit(curr->dest) + visit(curr->source) + visit(curr->size);
+  }
+  Index visitMemoryFill(MemoryFill* curr) {
+    return 6 + visit(curr->dest) + visit(curr->value) + visit(curr->size);
+  }
+  Index visitSIMDLoad(SIMDLoad* curr) { return 1 + visit(curr->ptr); }
+  Index visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+    return 1 + Index(curr->isStore()) + visit(curr->ptr) + visit(curr->vec);
+  }
+  Index visitSIMDReplace(SIMDReplace* curr) {
+    return 2 + visit(curr->vec) + visit(curr->value);
+  }
+  Index visitSIMDExtract(SIMDExtract* curr) { return 1 + visit(curr->vec); }
+  Index visitSIMDTernary(SIMDTernary* curr) {
+    Index ret = 0;
+    switch (curr->op) {
+      case Bitselect:
+      case SignSelectVec8x16:
+      case SignSelectVec16x8:
+      case SignSelectVec32x4:
+      case SignSelectVec64x2:
+        ret = 1;
+        break;
+      case QFMAF32x4:
+      case QFMSF32x4:
+      case QFMAF64x2:
+      case QFMSF64x2:
+        ret = 2;
+        break;
+    }
+    return ret + visit(curr->a) + visit(curr->b) + visit(curr->c);
+  }
+  Index visitSIMDShift(SIMDShift* curr) {
+    return 1 + visit(curr->vec) + visit(curr->shift);
+  }
+  Index visitSIMDShuffle(SIMDShuffle* curr) {
+    return 1 + visit(curr->left) + visit(curr->right);
+  }
+  Index visitPrefetch(Prefetch* curr) { return 0 + visit(curr->ptr); }
   Index visitRefNull(RefNull* curr) { return 1; }
   Index visitRefIsNull(RefIsNull* curr) { return 1 + visit(curr->value); }
   Index visitRefFunc(RefFunc* curr) { return 1; }
@@ -764,15 +546,86 @@
   }
   Index visitTry(Try* curr) {
     // We assume no exception will be thrown in most cases
-    return visit(curr->body);
+    return visit(curr->body) + maybeVisit(curr->catchBody);
   }
-  Index visitThrow(Throw* curr) { return 100; }
-  Index visitRethrow(Rethrow* curr) { return 100; }
+  Index visitThrow(Throw* curr) {
+    Index ret = 100;
+    for (auto* child : curr->operands) {
+      ret += visit(child);
+    }
+    return ret;
+  }
+  Index visitRethrow(Rethrow* curr) { return 100 + visit(curr->exnref); }
   Index visitBrOnExn(BrOnExn* curr) {
     return 1 + visit(curr->exnref) + curr->sent.size();
   }
+  Index visitTupleMake(TupleMake* curr) {
+    Index ret = 0;
+    for (auto* child : curr->operands) {
+      ret += visit(child);
+    }
+    return ret;
+  }
+  Index visitTupleExtract(TupleExtract* curr) { return visit(curr->tuple); }
+  Index visitPop(Pop* curr) { return 0; }
   Index visitNop(Nop* curr) { return 0; }
   Index visitUnreachable(Unreachable* curr) { return 0; }
+  Index visitDataDrop(DataDrop* curr) { return 5; }
+  Index visitI31New(I31New* curr) { return 3 + visit(curr->value); }
+  Index visitI31Get(I31Get* curr) { return 2 + visit(curr->i31); }
+  Index visitRefTest(RefTest* curr) {
+    return 2 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->rtt);
+  }
+  Index visitRefCast(RefCast* curr) {
+    return 2 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->rtt);
+  }
+  Index visitBrOnCast(BrOnCast* curr) {
+    return 3 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->rtt);
+  }
+  Index visitRttCanon(RttCanon* curr) {
+    // TODO: investigate actual RTT costs in VMs
+    return 1;
+  }
+  Index visitRttSub(RttSub* curr) {
+    // TODO: investigate actual RTT costs in VMs
+    return 2 + visit(curr->parent);
+  }
+  Index visitStructNew(StructNew* curr) {
+    // While allocation itself is almost free with generational GC, there is
+    // at least some baseline cost, plus writing the fields. (If we use default
+    // values for the fields, then it is possible they are all 0 and if so, we
+    // can get that almost for free as well, so don't add anything there.)
+    Index ret = 4 + visit(curr->rtt) + curr->operands.size();
+    for (auto* child : curr->operands) {
+      ret += visit(child);
+    }
+    return ret;
+  }
+  Index visitStructGet(StructGet* curr) {
+    return 1 + nullCheckCost(curr->ref) + visit(curr->ref);
+  }
+  Index visitStructSet(StructSet* curr) {
+    return 2 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->value);
+  }
+  Index visitArrayNew(ArrayNew* curr) {
+    return 4 + visit(curr->rtt) + visit(curr->size) + visit(curr->init);
+  }
+  Index visitArrayGet(ArrayGet* curr) {
+    return 1 + nullCheckCost(curr->ref) + visit(curr->ref) + visit(curr->index);
+  }
+  Index visitArraySet(ArraySet* curr) {
+    return 2 + nullCheckCost(curr->ref) + visit(curr->ref) +
+           visit(curr->index) + visit(curr->value);
+  }
+  Index visitArrayLen(ArrayLen* curr) {
+    return 1 + nullCheckCost(curr->ref) + visit(curr->ref);
+  }
+
+private:
+  Index nullCheckCost(Expression* ref) {
+    // A nullable type requires a bounds check in most VMs.
+    return ref->type.isNullable();
+  }
 };
 
 } // namespace wasm
diff --git a/binaryen/src/ir/effects.h b/binaryen/src/ir/effects.h
--- a/binaryen/src/ir/effects.h
+++ b/binaryen/src/ir/effects.h
@@ -25,15 +25,15 @@
 // Look for side effects, including control flow
 // TODO: optimize
 
-struct EffectAnalyzer
-  : public PostWalker<EffectAnalyzer, OverriddenVisitor<EffectAnalyzer>> {
+class EffectAnalyzer {
+public:
   EffectAnalyzer(const PassOptions& passOptions,
                  FeatureSet features,
                  Expression* ast = nullptr)
     : ignoreImplicitTraps(passOptions.ignoreImplicitTraps),
       debugInfo(passOptions.debugInfo), features(features) {
     if (ast) {
-      analyze(ast);
+      walk(ast);
     }
   }
 
@@ -41,12 +41,20 @@
   bool debugInfo;
   FeatureSet features;
 
-  void analyze(Expression* ast) {
-    breakTargets.clear();
-    walk(ast);
-    assert(tryDepth == 0);
+  // Walk an expression and all its children.
+  void walk(Expression* ast) {
+    pre();
+    InternalAnalyzer(*this).walk(ast);
+    post();
   }
 
+  // Visit an expression, without any children.
+  void visit(Expression* ast) {
+    pre();
+    InternalAnalyzer(*this).visit(ast);
+    post();
+  }
+
   // Core effect tracking
 
   // Definitely branches out of this expression, or does a return, etc.
@@ -63,10 +71,14 @@
   std::set<Name> globalsWritten;
   bool readsMemory = false;
   bool writesMemory = false;
-  // a load or div/rem, which may trap. we ignore trap differences, so it is ok
-  // to reorder these, but we can't remove them, as they count as side effects,
-  // and we can't move them in a way that would cause other noticeable (global)
-  // side effects
+  // A trap, either from an unreachable instruction, or from an implicit trap
+  // that we do not ignore (see below).
+  // Note that we ignore trap differences, so it is ok to reorder traps with
+  // each other, but it is not ok to remove them or reorder them with other
+  // effects in a noticeable way.
+  bool trap = false;
+  // A trap from an instruction like a load or div/rem, which may trap on corner
+  // cases. If we do not ignore implicit traps then these are counted as a trap.
   bool implicitTrap = false;
   // An atomic load/store/RMW/Cmpxchg or an operator that has a defined ordering
   // wrt atomics (e.g. memory.grow)
@@ -82,38 +94,6 @@
   // body. For example, (drop (exnref.pop)) should set this to true.
   bool danglingPop = false;
 
-  static void scan(EffectAnalyzer* self, Expression** currp) {
-    Expression* curr = *currp;
-    // We need to decrement try depth before catch starts, so handle it
-    // separately
-    if (curr->is<Try>()) {
-      self->pushTask(doVisitTry, currp);
-      self->pushTask(doEndCatch, currp);
-      self->pushTask(scan, &curr->cast<Try>()->catchBody);
-      self->pushTask(doStartCatch, currp);
-      self->pushTask(scan, &curr->cast<Try>()->body);
-      self->pushTask(doStartTry, currp);
-      return;
-    }
-    PostWalker<EffectAnalyzer, OverriddenVisitor<EffectAnalyzer>>::scan(self,
-                                                                        currp);
-  }
-
-  static void doStartTry(EffectAnalyzer* self, Expression** currp) {
-    self->tryDepth++;
-  }
-
-  static void doStartCatch(EffectAnalyzer* self, Expression** currp) {
-    assert(self->tryDepth > 0 && "try depth cannot be negative");
-    self->tryDepth--;
-    self->catchDepth++;
-  }
-
-  static void doEndCatch(EffectAnalyzer* self, Expression** currp) {
-    assert(self->catchDepth > 0 && "catch depth cannot be negative");
-    self->catchDepth--;
-  }
-
   // Helper functions to check for various effect types
 
   bool accessesLocal() const {
@@ -134,21 +114,21 @@
     return branchesOut || throws || hasExternalBreakTargets();
   }
 
-  bool hasGlobalSideEffects() const {
-    return calls || globalsWritten.size() > 0 || writesMemory || isAtomic ||
-           throws;
+  // Changes something in globally-stored state.
+  bool writesGlobalState() const {
+    return globalsWritten.size() || writesMemory || isAtomic || calls;
   }
+  bool readsGlobalState() const {
+    return globalsRead.size() || readsMemory || isAtomic || calls;
+  }
+
   bool hasSideEffects() const {
-    return hasGlobalSideEffects() || localsWritten.size() > 0 ||
-           transfersControlFlow() || implicitTrap || danglingPop;
+    return localsWritten.size() > 0 || danglingPop || writesGlobalState() ||
+           trap || throws || transfersControlFlow();
   }
   bool hasAnything() const {
     return hasSideEffects() || accessesLocal() || readsMemory ||
-           accessesGlobal() || isAtomic;
-  }
-
-  bool noticesGlobalSideEffects() const {
-    return calls || readsMemory || isAtomic || globalsRead.size();
+           accessesGlobal();
   }
 
   // check if we break to anything external from ourselves
@@ -160,7 +140,7 @@
     if ((transfersControlFlow() && other.hasSideEffects()) ||
         (other.transfersControlFlow() && hasSideEffects()) ||
         ((writesMemory || calls) && other.accessesMemory()) ||
-        (accessesMemory() && (other.writesMemory || other.calls)) ||
+        ((other.writesMemory || other.calls) && accessesMemory()) ||
         (danglingPop || other.danglingPop)) {
       return true;
     }
@@ -171,7 +151,7 @@
       return true;
     }
     for (auto local : localsWritten) {
-      if (other.localsWritten.count(local) || other.localsRead.count(local)) {
+      if (other.localsRead.count(local) || other.localsWritten.count(local)) {
         return true;
       }
     }
@@ -180,13 +160,13 @@
         return true;
       }
     }
-    if ((accessesGlobal() && other.calls) ||
-        (other.accessesGlobal() && calls)) {
+    if ((other.calls && accessesGlobal()) ||
+        (calls && other.accessesGlobal())) {
       return true;
     }
     for (auto global : globalsWritten) {
-      if (other.globalsWritten.count(global) ||
-          other.globalsRead.count(global)) {
+      if (other.globalsRead.count(global) ||
+          other.globalsWritten.count(global)) {
         return true;
       }
     }
@@ -195,14 +175,21 @@
         return true;
       }
     }
-    // we are ok to reorder implicit traps, but not conditionalize them
-    if ((implicitTrap && other.transfersControlFlow()) ||
-        (other.implicitTrap && transfersControlFlow())) {
+    // We are ok to reorder implicit traps, but not conditionalize them.
+    if ((trap && other.transfersControlFlow()) ||
+        (other.trap && transfersControlFlow())) {
       return true;
     }
-    // we can't reorder an implicit trap in a way that alters global state
-    if ((implicitTrap && other.hasGlobalSideEffects()) ||
-        (other.implicitTrap && hasGlobalSideEffects())) {
+    // Note that the above includes disallowing the reordering of a trap with an
+    // exception (as an exception can transfer control flow inside the current
+    // function, so transfersControlFlow would be true) - while we allow the
+    // reordering of traps with each other, we do not reorder exceptions with
+    // anything.
+    assert(!((trap && other.throws) || (throws && other.trap)));
+    // We can't reorder an implicit trap in a way that could alter what global
+    // state is modified.
+    if ((trap && other.writesGlobalState()) ||
+        (other.trap && writesGlobalState())) {
       return true;
     }
     return false;
@@ -213,6 +200,7 @@
     calls = calls || other.calls;
     readsMemory = readsMemory || other.readsMemory;
     writesMemory = writesMemory || other.writesMemory;
+    trap = trap || other.trap;
     implicitTrap = implicitTrap || other.implicitTrap;
     isAtomic = isAtomic || other.isAtomic;
     throws = throws || other.throws;
@@ -255,167 +243,205 @@
 
   std::set<Name> breakTargets;
 
-  void visitBlock(Block* curr) {
-    if (curr->name.is()) {
-      breakTargets.erase(curr->name); // these were internal breaks
+private:
+  struct InternalAnalyzer
+    : public PostWalker<InternalAnalyzer, OverriddenVisitor<InternalAnalyzer>> {
+
+    EffectAnalyzer& parent;
+
+    InternalAnalyzer(EffectAnalyzer& parent) : parent(parent) {}
+
+    static void scan(InternalAnalyzer* self, Expression** currp) {
+      Expression* curr = *currp;
+      // We need to decrement try depth before catch starts, so handle it
+      // separately
+      if (curr->is<Try>()) {
+        self->pushTask(doVisitTry, currp);
+        self->pushTask(doEndCatch, currp);
+        self->pushTask(scan, &curr->cast<Try>()->catchBody);
+        self->pushTask(doStartCatch, currp);
+        self->pushTask(scan, &curr->cast<Try>()->body);
+        self->pushTask(doStartTry, currp);
+        return;
+      }
+      PostWalker<InternalAnalyzer, OverriddenVisitor<InternalAnalyzer>>::scan(
+        self, currp);
     }
-  }
-  void visitIf(If* curr) {}
-  void visitLoop(Loop* curr) {
-    if (curr->name.is()) {
-      breakTargets.erase(curr->name); // these were internal breaks
+
+    static void doStartTry(InternalAnalyzer* self, Expression** currp) {
+      self->parent.tryDepth++;
     }
-    // if the loop is unreachable, then there is branching control flow:
-    //  (1) if the body is unreachable because of a (return), uncaught (br)
-    //      etc., then we already noted branching, so it is ok to mark it again
-    //      (if we have *caught* (br)s, then they did not lead to the loop body
-    //      being unreachable). (same logic applies to blocks)
-    //  (2) if the loop is unreachable because it only has branches up to the
-    //      loop top, but no way to get out, then it is an infinite loop, and we
-    //      consider that a branching side effect (note how the same logic does
-    //      not apply to blocks).
-    if (curr->type == Type::unreachable) {
-      branchesOut = true;
+
+    static void doStartCatch(InternalAnalyzer* self, Expression** currp) {
+      assert(self->parent.tryDepth > 0 && "try depth cannot be negative");
+      self->parent.tryDepth--;
+      self->parent.catchDepth++;
     }
-  }
-  void visitBreak(Break* curr) { breakTargets.insert(curr->name); }
-  void visitSwitch(Switch* curr) {
-    for (auto name : curr->targets) {
-      breakTargets.insert(name);
+
+    static void doEndCatch(InternalAnalyzer* self, Expression** currp) {
+      assert(self->parent.catchDepth > 0 && "catch depth cannot be negative");
+      self->parent.catchDepth--;
     }
-    breakTargets.insert(curr->default_);
-  }
 
-  void visitCall(Call* curr) {
-    calls = true;
-    // When EH is enabled, any call can throw.
-    if (features.hasExceptionHandling() && tryDepth == 0) {
-      throws = true;
+    void visitBlock(Block* curr) {
+      if (curr->name.is()) {
+        parent.breakTargets.erase(curr->name); // these were internal breaks
+      }
     }
-    if (curr->isReturn) {
-      branchesOut = true;
+    void visitIf(If* curr) {}
+    void visitLoop(Loop* curr) {
+      if (curr->name.is()) {
+        parent.breakTargets.erase(curr->name); // these were internal breaks
+      }
+      // if the loop is unreachable, then there is branching control flow:
+      //  (1) if the body is unreachable because of a (return), uncaught (br)
+      //      etc., then we already noted branching, so it is ok to mark it
+      //      again (if we have *caught* (br)s, then they did not lead to the
+      //      loop body being unreachable). (same logic applies to blocks)
+      //  (2) if the loop is unreachable because it only has branches up to the
+      //      loop top, but no way to get out, then it is an infinite loop, and
+      //      we consider that a branching side effect (note how the same logic
+      //      does not apply to blocks).
+      if (curr->type == Type::unreachable) {
+        parent.branchesOut = true;
+      }
     }
-    if (debugInfo) {
-      // debugInfo call imports must be preserved very strongly, do not
-      // move code around them
-      // FIXME: we could check if the call is to an import
-      branchesOut = true;
+    void visitBreak(Break* curr) { parent.breakTargets.insert(curr->name); }
+    void visitSwitch(Switch* curr) {
+      for (auto name : curr->targets) {
+        parent.breakTargets.insert(name);
+      }
+      parent.breakTargets.insert(curr->default_);
     }
-  }
-  void visitCallIndirect(CallIndirect* curr) {
-    calls = true;
-    if (features.hasExceptionHandling() && tryDepth == 0) {
-      throws = true;
+
+    void visitCall(Call* curr) {
+      parent.calls = true;
+      // When EH is enabled, any call can throw.
+      if (parent.features.hasExceptionHandling() && parent.tryDepth == 0) {
+        parent.throws = true;
+      }
+      if (curr->isReturn) {
+        parent.branchesOut = true;
+      }
+      if (parent.debugInfo) {
+        // debugInfo call imports must be preserved very strongly, do not
+        // move code around them
+        // FIXME: we could check if the call is to an import
+        parent.branchesOut = true;
+      }
     }
-    if (curr->isReturn) {
-      branchesOut = true;
+    void visitCallIndirect(CallIndirect* curr) {
+      parent.calls = true;
+      if (parent.features.hasExceptionHandling() && parent.tryDepth == 0) {
+        parent.throws = true;
+      }
+      if (curr->isReturn) {
+        parent.branchesOut = true;
+      }
     }
-  }
-  void visitLocalGet(LocalGet* curr) { localsRead.insert(curr->index); }
-  void visitLocalSet(LocalSet* curr) { localsWritten.insert(curr->index); }
-  void visitGlobalGet(GlobalGet* curr) { globalsRead.insert(curr->name); }
-  void visitGlobalSet(GlobalSet* curr) { globalsWritten.insert(curr->name); }
-  void visitLoad(Load* curr) {
-    readsMemory = true;
-    isAtomic |= curr->isAtomic;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitLocalGet(LocalGet* curr) {
+      parent.localsRead.insert(curr->index);
     }
-  }
-  void visitStore(Store* curr) {
-    writesMemory = true;
-    isAtomic |= curr->isAtomic;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitLocalSet(LocalSet* curr) {
+      parent.localsWritten.insert(curr->index);
     }
-  }
-  void visitAtomicRMW(AtomicRMW* curr) {
-    readsMemory = true;
-    writesMemory = true;
-    isAtomic = true;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitGlobalGet(GlobalGet* curr) {
+      parent.globalsRead.insert(curr->name);
     }
-  }
-  void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
-    readsMemory = true;
-    writesMemory = true;
-    isAtomic = true;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitGlobalSet(GlobalSet* curr) {
+      parent.globalsWritten.insert(curr->name);
     }
-  }
-  void visitAtomicWait(AtomicWait* curr) {
-    readsMemory = true;
-    // AtomicWait doesn't strictly write memory, but it does modify the waiters
-    // list associated with the specified address, which we can think of as a
-    // write.
-    writesMemory = true;
-    isAtomic = true;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitLoad(Load* curr) {
+      parent.readsMemory = true;
+      parent.isAtomic |= curr->isAtomic;
+      parent.implicitTrap = true;
     }
-  }
-  void visitAtomicNotify(AtomicNotify* curr) {
-    // AtomicNotify doesn't strictly write memory, but it does modify the
-    // waiters list associated with the specified address, which we can think of
-    // as a write.
-    readsMemory = true;
-    writesMemory = true;
-    isAtomic = true;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitStore(Store* curr) {
+      parent.writesMemory = true;
+      parent.isAtomic |= curr->isAtomic;
+      parent.implicitTrap = true;
     }
-  }
-  void visitAtomicFence(AtomicFence* curr) {
-    // AtomicFence should not be reordered with any memory operations, so we set
-    // these to true.
-    readsMemory = true;
-    writesMemory = true;
-    isAtomic = true;
-  }
-  void visitSIMDExtract(SIMDExtract* curr) {}
-  void visitSIMDReplace(SIMDReplace* curr) {}
-  void visitSIMDShuffle(SIMDShuffle* curr) {}
-  void visitSIMDTernary(SIMDTernary* curr) {}
-  void visitSIMDShift(SIMDShift* curr) {}
-  void visitSIMDLoad(SIMDLoad* curr) {
-    readsMemory = true;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitAtomicRMW(AtomicRMW* curr) {
+      parent.readsMemory = true;
+      parent.writesMemory = true;
+      parent.isAtomic = true;
+      parent.implicitTrap = true;
     }
-  }
-  void visitMemoryInit(MemoryInit* curr) {
-    writesMemory = true;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+      parent.readsMemory = true;
+      parent.writesMemory = true;
+      parent.isAtomic = true;
+      parent.implicitTrap = true;
     }
-  }
-  void visitDataDrop(DataDrop* curr) {
-    // data.drop does not actually write memory, but it does alter the size of
-    // a segment, which can be noticeable later by memory.init, so we need to
-    // mark it as having a global side effect of some kind.
-    writesMemory = true;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitAtomicWait(AtomicWait* curr) {
+      parent.readsMemory = true;
+      // AtomicWait doesn't strictly write memory, but it does modify the
+      // waiters list associated with the specified address, which we can think
+      // of as a write.
+      parent.writesMemory = true;
+      parent.isAtomic = true;
+      parent.implicitTrap = true;
     }
-  }
-  void visitMemoryCopy(MemoryCopy* curr) {
-    readsMemory = true;
-    writesMemory = true;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitAtomicNotify(AtomicNotify* curr) {
+      // AtomicNotify doesn't strictly write memory, but it does modify the
+      // waiters list associated with the specified address, which we can think
+      // of as a write.
+      parent.readsMemory = true;
+      parent.writesMemory = true;
+      parent.isAtomic = true;
+      parent.implicitTrap = true;
     }
-  }
-  void visitMemoryFill(MemoryFill* curr) {
-    writesMemory = true;
-    if (!ignoreImplicitTraps) {
-      implicitTrap = true;
+    void visitAtomicFence(AtomicFence* curr) {
+      // AtomicFence should not be reordered with any memory operations, so we
+      // set these to true.
+      parent.readsMemory = true;
+      parent.writesMemory = true;
+      parent.isAtomic = true;
     }
-  }
-  void visitConst(Const* curr) {}
-  void visitUnary(Unary* curr) {
-    if (!ignoreImplicitTraps) {
+    void visitSIMDExtract(SIMDExtract* curr) {}
+    void visitSIMDReplace(SIMDReplace* curr) {}
+    void visitSIMDShuffle(SIMDShuffle* curr) {}
+    void visitSIMDTernary(SIMDTernary* curr) {}
+    void visitSIMDShift(SIMDShift* curr) {}
+    void visitSIMDLoad(SIMDLoad* curr) {
+      parent.readsMemory = true;
+      parent.implicitTrap = true;
+    }
+    void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+      if (curr->isLoad()) {
+        parent.readsMemory = true;
+      } else {
+        parent.writesMemory = true;
+      }
+      parent.implicitTrap = true;
+    }
+    void visitPrefetch(Prefetch* curr) {
+      // Do not reorder with respect to other memory ops
+      parent.writesMemory = true;
+      parent.readsMemory = true;
+    }
+    void visitMemoryInit(MemoryInit* curr) {
+      parent.writesMemory = true;
+      parent.implicitTrap = true;
+    }
+    void visitDataDrop(DataDrop* curr) {
+      // data.drop does not actually write memory, but it does alter the size of
+      // a segment, which can be noticeable later by memory.init, so we need to
+      // mark it as having a global side effect of some kind.
+      parent.writesMemory = true;
+      parent.implicitTrap = true;
+    }
+    void visitMemoryCopy(MemoryCopy* curr) {
+      parent.readsMemory = true;
+      parent.writesMemory = true;
+      parent.implicitTrap = true;
+    }
+    void visitMemoryFill(MemoryFill* curr) {
+      parent.writesMemory = true;
+      parent.implicitTrap = true;
+    }
+    void visitConst(Const* curr) {}
+    void visitUnary(Unary* curr) {
       switch (curr->op) {
         case TruncSFloat32ToInt32:
         case TruncSFloat32ToInt64:
@@ -425,16 +451,13 @@
         case TruncSFloat64ToInt64:
         case TruncUFloat64ToInt32:
         case TruncUFloat64ToInt64: {
-          implicitTrap = true;
+          parent.implicitTrap = true;
           break;
         }
-        default: {
-        }
+        default: {}
       }
     }
-  }
-  void visitBinary(Binary* curr) {
-    if (!ignoreImplicitTraps) {
+    void visitBinary(Binary* curr) {
       switch (curr->op) {
         case DivSInt32:
         case DivUInt32:
@@ -444,100 +467,130 @@
         case DivUInt64:
         case RemSInt64:
         case RemUInt64: {
-          implicitTrap = true;
+          // div and rem may contain implicit trap only if RHS is
+          // non-constant or constant which equal zero or -1 for
+          // signed divisions. Reminder traps only with zero
+          // divider.
+          if (auto* c = curr->right->dynCast<Const>()) {
+            if (c->value.isZero()) {
+              parent.implicitTrap = true;
+            } else if ((curr->op == DivSInt32 || curr->op == DivSInt64) &&
+                       c->value.getInteger() == -1LL) {
+              parent.implicitTrap = true;
+            }
+          } else {
+            parent.implicitTrap = true;
+          }
           break;
         }
-        default: {
-        }
+        default: {}
       }
     }
-  }
-  void visitSelect(Select* curr) {}
-  void visitDrop(Drop* curr) {}
-  void visitReturn(Return* curr) { branchesOut = true; }
-  void visitMemorySize(MemorySize* curr) {
-    // memory.size accesses the size of the memory, and thus can be modeled as
-    // reading memory
-    readsMemory = true;
-    // Atomics are sequentially consistent with memory.size.
-    isAtomic = true;
-  }
-  void visitMemoryGrow(MemoryGrow* curr) {
-    calls = true;
-    // memory.grow technically does a read-modify-write operation on the memory
-    // size in the successful case, modifying the set of valid addresses, and
-    // just a read operation in the failure case
-    readsMemory = true;
-    writesMemory = true;
-    // Atomics are also sequentially consistent with memory.grow.
-    isAtomic = true;
-  }
-  void visitRefNull(RefNull* curr) {}
-  void visitRefIsNull(RefIsNull* curr) {}
-  void visitRefFunc(RefFunc* curr) {}
-  void visitRefEq(RefEq* curr) {}
-  void visitTry(Try* curr) {}
-  void visitThrow(Throw* curr) {
-    if (tryDepth == 0) {
-      throws = true;
+    void visitSelect(Select* curr) {}
+    void visitDrop(Drop* curr) {}
+    void visitReturn(Return* curr) { parent.branchesOut = true; }
+    void visitMemorySize(MemorySize* curr) {
+      // memory.size accesses the size of the memory, and thus can be modeled as
+      // reading memory
+      parent.readsMemory = true;
+      // Atomics are sequentially consistent with memory.size.
+      parent.isAtomic = true;
     }
-  }
-  void visitRethrow(Rethrow* curr) {
-    if (tryDepth == 0) {
-      throws = true;
+    void visitMemoryGrow(MemoryGrow* curr) {
+      parent.calls = true;
+      // memory.grow technically does a read-modify-write operation on the
+      // memory size in the successful case, modifying the set of valid
+      // addresses, and just a read operation in the failure case
+      parent.readsMemory = true;
+      parent.writesMemory = true;
+      // Atomics are also sequentially consistent with memory.grow.
+      parent.isAtomic = true;
     }
-    if (!ignoreImplicitTraps) { // rethrow traps when the arg is null
-      implicitTrap = true;
+    void visitRefNull(RefNull* curr) {}
+    void visitRefIsNull(RefIsNull* curr) {}
+    void visitRefFunc(RefFunc* curr) {}
+    void visitRefEq(RefEq* curr) {}
+    void visitTry(Try* curr) {}
+    void visitThrow(Throw* curr) {
+      if (parent.tryDepth == 0) {
+        parent.throws = true;
+      }
     }
-  }
-  void visitBrOnExn(BrOnExn* curr) {
-    breakTargets.insert(curr->name);
-    if (!ignoreImplicitTraps) { // br_on_exn traps when the arg is null
-      implicitTrap = true;
+    void visitRethrow(Rethrow* curr) {
+      if (parent.tryDepth == 0) {
+        parent.throws = true;
+      }
+      // traps when the arg is null
+      parent.implicitTrap = true;
     }
-  }
-  void visitNop(Nop* curr) {}
-  void visitUnreachable(Unreachable* curr) { branchesOut = true; }
-  void visitPop(Pop* curr) {
-    if (catchDepth == 0) {
-      danglingPop = true;
+    void visitBrOnExn(BrOnExn* curr) {
+      parent.breakTargets.insert(curr->name);
+      // traps when the arg is null
+      parent.implicitTrap = true;
     }
-  }
-  void visitTupleMake(TupleMake* curr) {}
-  void visitTupleExtract(TupleExtract* curr) {}
-  void visitI31New(I31New* curr) {}
-  void visitI31Get(I31Get* curr) {}
-  void visitRefTest(RefTest* curr) { WASM_UNREACHABLE("TODO (gc): ref.test"); }
-  void visitRefCast(RefCast* curr) { WASM_UNREACHABLE("TODO (gc): ref.cast"); }
-  void visitBrOnCast(BrOnCast* curr) {
-    WASM_UNREACHABLE("TODO (gc): br_on_cast");
-  }
-  void visitRttCanon(RttCanon* curr) {
-    WASM_UNREACHABLE("TODO (gc): rtt.canon");
-  }
-  void visitRttSub(RttSub* curr) { WASM_UNREACHABLE("TODO (gc): rtt.sub"); }
-  void visitStructNew(StructNew* curr) {
-    WASM_UNREACHABLE("TODO (gc): struct.new");
-  }
-  void visitStructGet(StructGet* curr) {
-    WASM_UNREACHABLE("TODO (gc): struct.get");
-  }
-  void visitStructSet(StructSet* curr) {
-    WASM_UNREACHABLE("TODO (gc): struct.set");
-  }
-  void visitArrayNew(ArrayNew* curr) {
-    WASM_UNREACHABLE("TODO (gc): array.new");
-  }
-  void visitArrayGet(ArrayGet* curr) {
-    WASM_UNREACHABLE("TODO (gc): array.get");
-  }
-  void visitArraySet(ArraySet* curr) {
-    WASM_UNREACHABLE("TODO (gc): array.set");
-  }
-  void visitArrayLen(ArrayLen* curr) {
-    WASM_UNREACHABLE("TODO (gc): array.len");
-  }
+    void visitNop(Nop* curr) {}
+    void visitUnreachable(Unreachable* curr) { parent.trap = true; }
+    void visitPop(Pop* curr) {
+      if (parent.catchDepth == 0) {
+        parent.danglingPop = true;
+      }
+    }
+    void visitTupleMake(TupleMake* curr) {}
+    void visitTupleExtract(TupleExtract* curr) {}
+    void visitI31New(I31New* curr) {}
+    void visitI31Get(I31Get* curr) {}
+    void visitCallRef(CallRef* curr) {
+      parent.calls = true;
+      if (parent.features.hasExceptionHandling() && parent.tryDepth == 0) {
+        parent.throws = true;
+      }
+      if (curr->isReturn) {
+        parent.branchesOut = true;
+      }
+      // traps when the arg is null
+      parent.implicitTrap = true;
+    }
+    void visitRefTest(RefTest* curr) {}
+    void visitRefCast(RefCast* curr) {
+      // Traps if the ref is not null and it has an invalid rtt.
+      parent.implicitTrap = true;
+    }
+    void visitBrOnCast(BrOnCast* curr) {
+      parent.breakTargets.insert(curr->name);
+    }
+    void visitRttCanon(RttCanon* curr) {}
+    void visitRttSub(RttSub* curr) {}
+    void visitStructNew(StructNew* curr) {}
+    void visitStructGet(StructGet* curr) {
+      // traps when the arg is null
+      if (curr->ref->type.isNullable()) {
+        parent.implicitTrap = true;
+      }
+    }
+    void visitStructSet(StructSet* curr) {
+      // traps when the arg is null
+      if (curr->ref->type.isNullable()) {
+        parent.implicitTrap = true;
+      }
+    }
+    void visitArrayNew(ArrayNew* curr) {}
+    void visitArrayGet(ArrayGet* curr) {
+      // traps when the arg is null or the index out of bounds
+      parent.implicitTrap = true;
+    }
+    void visitArraySet(ArraySet* curr) {
+      // traps when the arg is null or the index out of bounds
+      parent.implicitTrap = true;
+    }
+    void visitArrayLen(ArrayLen* curr) {
+      // traps when the arg is null
+      if (curr->ref->type.isNullable()) {
+        parent.implicitTrap = true;
+      }
+    }
+  };
 
+public:
   // Helpers
 
   static bool canReorder(const PassOptions& passOptions,
@@ -611,6 +664,19 @@
   void ignoreBranches() {
     branchesOut = false;
     breakTargets.clear();
+  }
+
+private:
+  void pre() { breakTargets.clear(); }
+
+  void post() {
+    assert(tryDepth == 0);
+
+    if (ignoreImplicitTraps) {
+      implicitTrap = false;
+    } else if (implicitTrap) {
+      trap = true;
+    }
   }
 };
 
diff --git a/binaryen/src/ir/features.h b/binaryen/src/ir/features.h
--- a/binaryen/src/ir/features.h
+++ b/binaryen/src/ir/features.h
@@ -57,8 +57,6 @@
     case AnyTrueVecI32x4:
     case AllTrueVecI32x4:
     case NegVecI64x2:
-    case AnyTrueVecI64x2:
-    case AllTrueVecI64x2:
     case AbsVecF32x4:
     case NegVecF32x4:
     case SqrtVecF32x4:
diff --git a/binaryen/src/ir/global-utils.h b/binaryen/src/ir/global-utils.h
--- a/binaryen/src/ir/global-utils.h
+++ b/binaryen/src/ir/global-utils.h
@@ -56,13 +56,14 @@
 inline bool canInitializeGlobal(const Expression* curr) {
   if (auto* tuple = curr->dynCast<TupleMake>()) {
     for (auto* op : tuple->operands) {
-      if (!Properties::isSingleConstantExpression(op) && !op->is<GlobalGet>()) {
+      if (!canInitializeGlobal(op)) {
         return false;
       }
     }
     return true;
   }
-  return Properties::isSingleConstantExpression(curr) || curr->is<GlobalGet>();
+  return Properties::isSingleConstantExpression(curr) ||
+         curr->is<GlobalGet>() || curr->is<RttCanon>() || curr->is<RttSub>();
 }
 
 } // namespace GlobalUtils
diff --git a/binaryen/src/ir/module-splitting.cpp b/binaryen/src/ir/module-splitting.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/module-splitting.cpp
@@ -0,0 +1,595 @@
+/*
+ * 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.
+ */
+
+// The process of module splitting involves these steps:
+//
+//   1. Create the new secondary module.
+//
+//   2. Export globals, events, tables, and memories from the primary module and
+//      import them in the secondary module.
+//
+//   3. Move the deferred functions from the primary to the secondary module.
+//
+//   4. For any secondary function exported from the primary module, export in
+//      its place a trampoline function that makes an indirect call to its
+//      placeholder function (and eventually to the original secondary
+//      function), allocating a new table slot for the placeholder if necessary.
+//
+//   5. Rewrite direct calls from primary functions to secondary functions to be
+//      indirect calls to their placeholder functions (and eventually to their
+//      original secondary functions), allocating new table slots for the
+//      placeholders if necessary.
+//
+//   6. For each primary function directly called from a secondary function,
+//      export the primary function if it is not already exported and import it
+//      into the secondary module.
+//
+//   7. Replace all references to secondary functions in the primary module's
+//      table segments with references to imported placeholder functions.
+//
+//   8. Create new active table segments in the secondary module that will
+//      replace all the placeholder function references in the table with
+//      references to their corresponding secondary functions upon
+//      instantiation.
+//
+// Functions can be used or referenced three ways in a WebAssembly module: they
+// can be exported, called, or placed in a table. The above procedure introduces
+// a layer of indirection to each of those mechanisms that removes all
+// references to secondary functions from the primary module but restores the
+// original program's semantics once the secondary module is instantiated. As
+// more mechanisms that reference functions are added in the future, such as
+// ref.func instructions, they will have to be modified to use a similar layer
+// of indirection.
+//
+// The code as currently written makes a few assumptions about the module that
+// is being split:
+//
+//   1. It assumes that mutable-globals is allowed. This could be worked around
+//      by introducing wrapper functions for globals and rewriting secondary
+//      code that accesses them, but now that mutable-globals is shipped on all
+//      browsers, hopefully that extra complexity won't be necessary.
+//
+//   2. It assumes that either all table segment offsets are constants or there
+//      is exactly one segment that may have a non-constant offset. It also
+//      assumes that all segments are active segments (although Binaryen does
+//      not yet support passive table segments anyway).
+//
+//   3. It assumes that each function appears in the table at most once. This
+//      isn't necessarily true in general or even for LLVM output after function
+//      deduplication. Relaxing this assumption would just require slightly more
+//      complex code, so it is a good candidate for a follow up PR.
+
+#include "ir/module-splitting.h"
+#include "ir/manipulation.h"
+#include "ir/module-utils.h"
+#include "ir/names.h"
+#include "pass.h"
+#include "wasm-builder.h"
+#include "wasm.h"
+
+namespace std {
+
+// Used in ModuleSplitter::shareImportableItems
+template<> struct hash<pair<wasm::ExternalKind, wasm::Name>> {
+  size_t operator()(const pair<wasm::ExternalKind, wasm::Name>& p) const {
+    auto digest = wasm::hash(p.first);
+    wasm::rehash(digest, p.second);
+    return digest;
+  }
+};
+
+} // namespace std
+
+namespace wasm {
+
+namespace ModuleSplitting {
+
+namespace {
+
+template<class F> void forEachElement(Table& table, F f) {
+  for (auto& segment : table.segments) {
+    Name base = "";
+    Index offset = 0;
+    if (auto* c = segment.offset->dynCast<Const>()) {
+      offset = c->value.geti32();
+    } else if (auto* g = segment.offset->dynCast<GlobalGet>()) {
+      base = g->name;
+    }
+    for (size_t i = 0; i < segment.data.size(); ++i) {
+      f(base, offset + i, segment.data[i]);
+    }
+  }
+}
+
+struct TableSlotManager {
+  struct Slot {
+    // If `global` is empty, then this slot is at a statically known index.
+    Name global;
+    Index index = 0;
+
+    // Generate code to compute the index of this table slot
+    Expression* makeExpr(Module& module);
+  };
+  Module& module;
+  Table& table;
+  Table::Segment* activeSegment = nullptr;
+  Slot activeBase;
+  std::map<Name, Slot> funcIndices;
+
+  TableSlotManager(Module& module);
+
+  // Returns the table index for `func`, allocating a new index if necessary.
+  Slot getSlot(Name func);
+  void addSlot(Name func, Slot slot);
+};
+
+Expression* TableSlotManager::Slot::makeExpr(Module& module) {
+  Builder builder(module);
+  auto makeIndex = [&]() { return builder.makeConst(int32_t(index)); };
+  if (global.size()) {
+    Expression* getBase = builder.makeGlobalGet(global, Type::i32);
+    return index == 0 ? getBase
+                      : builder.makeBinary(AddInt32, getBase, makeIndex());
+  } else {
+    return makeIndex();
+  }
+}
+
+void TableSlotManager::addSlot(Name func, Slot slot) {
+  auto it = funcIndices.insert(std::make_pair(func, slot));
+  assert(it.second && "Function already has multiple table slots");
+}
+
+TableSlotManager::TableSlotManager(Module& module)
+  : module(module), table(module.table) {
+
+  // If there is exactly one table segment and that segment has a non-constant
+  // offset, append new items to the end of that segment. In all other cases,
+  // append new items at constant offsets after all existing items at constant
+  // offsets.
+  if (table.segments.size() == 1 && !table.segments[0].offset->is<Const>()) {
+    assert(table.segments[0].offset->is<GlobalGet>() &&
+           "Unexpected initializer instruction");
+    activeSegment = &table.segments[0];
+    activeBase = {table.segments[0].offset->cast<GlobalGet>()->name, 0};
+  } else {
+    // Finds the segment with the highest occupied table slot so that new items
+    // can be inserted contiguously at the end of it without accidentally
+    // overwriting any other items. TODO: be more clever about filling gaps in
+    // the table, if that is ever useful.
+    Index maxIndex = 0;
+    for (auto& segment : table.segments) {
+      assert(segment.offset->is<Const>() &&
+             "Unexpected non-const segment offset with multiple segments");
+      Index segmentBase = segment.offset->cast<Const>()->value.geti32();
+      if (segmentBase + segment.data.size() >= maxIndex) {
+        maxIndex = segmentBase + segment.data.size();
+        activeSegment = &segment;
+        activeBase = {"", segmentBase};
+      }
+    }
+  }
+  // Initialize funcIndices with the functions already in the table.
+  forEachElement(table, [&](Name base, Index offset, Name func) {
+    addSlot(func, {base, offset});
+  });
+}
+
+TableSlotManager::Slot TableSlotManager::getSlot(Name func) {
+  auto slotIt = funcIndices.find(func);
+  if (slotIt != funcIndices.end()) {
+    return slotIt->second;
+  }
+
+  // If there are no segments yet, allocate one.
+  if (activeSegment == nullptr) {
+    table.exists = true;
+    assert(table.segments.size() == 0);
+    table.segments.emplace_back(Builder(module).makeConst(int32_t(0)));
+    activeSegment = &table.segments.back();
+  }
+
+  Slot newSlot = {activeBase.global,
+                  activeBase.index + Index(activeSegment->data.size())};
+  activeSegment->data.push_back(func);
+  addSlot(func, newSlot);
+  if (table.initial <= newSlot.index) {
+    table.initial = newSlot.index + 1;
+  }
+  if (table.max <= newSlot.index) {
+    table.max = newSlot.index + 1;
+  }
+  return newSlot;
+}
+
+struct ModuleSplitter {
+  const Config& config;
+  std::unique_ptr<Module> secondaryPtr;
+
+  Module& primary;
+  Module& secondary;
+
+  const std::pair<std::set<Name>, std::set<Name>> classifiedFuncs;
+  const std::set<Name>& primaryFuncs;
+  const std::set<Name>& secondaryFuncs;
+
+  TableSlotManager tableManager;
+
+  // Map from internal function names to (one of) their corresponding export
+  // names.
+  std::map<Name, Name> exportedPrimaryFuncs;
+
+  // Initialization helpers
+  static std::unique_ptr<Module> initSecondary(const Module& primary);
+  static std::pair<std::set<Name>, std::set<Name>>
+  classifyFunctions(const Module& primary, const Config& config);
+  static std::map<Name, Name> initExportedPrimaryFuncs(const Module& primary);
+
+  // Other helpers
+  void exportImportFunction(Name func);
+
+  // Main splitting steps
+  void moveSecondaryFunctions();
+  void thunkExportedSecondaryFunctions();
+  void indirectCallsToSecondaryFunctions();
+  void exportImportCalledPrimaryFunctions();
+  void setupTablePatching();
+  void shareImportableItems();
+
+  ModuleSplitter(Module& primary, const Config& config)
+    : config(config), secondaryPtr(initSecondary(primary)), primary(primary),
+      secondary(*secondaryPtr),
+      classifiedFuncs(classifyFunctions(primary, config)),
+      primaryFuncs(classifiedFuncs.first),
+      secondaryFuncs(classifiedFuncs.second), tableManager(primary),
+      exportedPrimaryFuncs(initExportedPrimaryFuncs(primary)) {
+    moveSecondaryFunctions();
+    thunkExportedSecondaryFunctions();
+    indirectCallsToSecondaryFunctions();
+    exportImportCalledPrimaryFunctions();
+    setupTablePatching();
+    shareImportableItems();
+  }
+};
+
+std::unique_ptr<Module> ModuleSplitter::initSecondary(const Module& primary) {
+  // Create the secondary module and copy trivial properties.
+  auto secondary = std::make_unique<Module>();
+  secondary->features = primary.features;
+  secondary->hasFeaturesSection = primary.hasFeaturesSection;
+  return secondary;
+}
+
+std::pair<std::set<Name>, std::set<Name>>
+ModuleSplitter::classifyFunctions(const Module& primary, const Config& config) {
+  std::set<Name> primaryFuncs, secondaryFuncs;
+  for (auto& func : primary.functions) {
+    if (func->imported() || config.primaryFuncs.count(func->name)) {
+      primaryFuncs.insert(func->name);
+    } else {
+      assert(func->name != primary.start && "The start function must be kept");
+      secondaryFuncs.insert(func->name);
+    }
+  }
+  return std::make_pair(primaryFuncs, secondaryFuncs);
+}
+
+std::map<Name, Name>
+ModuleSplitter::initExportedPrimaryFuncs(const Module& primary) {
+  std::map<Name, Name> functionExportNames;
+  for (auto& ex : primary.exports) {
+    if (ex->kind == ExternalKind::Function) {
+      functionExportNames[ex->value] = ex->name;
+    }
+  }
+  return functionExportNames;
+}
+
+void ModuleSplitter::exportImportFunction(Name funcName) {
+  Name exportName;
+  // If the function is already exported, use the existing export name.
+  // Otherwise, create a new export for it.
+  auto exportIt = exportedPrimaryFuncs.find(funcName);
+  if (exportIt != exportedPrimaryFuncs.end()) {
+    exportName = exportIt->second;
+  } else {
+    exportName = Names::getValidExportName(
+      primary, config.newExportPrefix + funcName.c_str());
+    primary.addExport(
+      Builder::makeExport(exportName, funcName, ExternalKind::Function));
+    exportedPrimaryFuncs[funcName] = exportName;
+  }
+  // Import the function if it is not already imported into the secondary
+  // module.
+  if (secondary.getFunctionOrNull(funcName) == nullptr) {
+    auto func =
+      Builder::makeFunction(funcName, primary.getFunction(funcName)->sig, {});
+    func->module = config.importNamespace;
+    func->base = exportName;
+    secondary.addFunction(std::move(func));
+  }
+}
+
+void ModuleSplitter::moveSecondaryFunctions() {
+  // Move the specified functions from the primary to the secondary module.
+  for (auto funcName : secondaryFuncs) {
+    auto* func = primary.getFunction(funcName);
+    ModuleUtils::copyFunction(func, secondary);
+    primary.removeFunction(funcName);
+  }
+}
+
+void ModuleSplitter::thunkExportedSecondaryFunctions() {
+  // Update exports of secondary functions in the primary module to export
+  // wrapper functions that indirectly call the secondary functions. We are
+  // adding secondary function names to the primary table here, but they will be
+  // replaced with placeholder functions later along with any references to
+  // secondary functions that were already in the table.
+  Builder builder(primary);
+  for (auto& ex : primary.exports) {
+    if (ex->kind != ExternalKind::Function ||
+        !secondaryFuncs.count(ex->value)) {
+      continue;
+    }
+    Name secondaryFunc = ex->value;
+    if (primary.getFunctionOrNull(secondaryFunc)) {
+      // We've already created a thunk for this function
+      continue;
+    }
+    auto tableSlot = tableManager.getSlot(secondaryFunc);
+    auto func = std::make_unique<Function>();
+
+    func->name = secondaryFunc;
+    func->sig = secondary.getFunction(secondaryFunc)->sig;
+    std::vector<Expression*> args;
+    for (size_t i = 0, size = func->sig.params.size(); i < size; ++i) {
+      args.push_back(builder.makeLocalGet(i, func->sig.params[i]));
+    }
+    func->body =
+      builder.makeCallIndirect(tableSlot.makeExpr(primary), args, func->sig);
+    primary.addFunction(std::move(func));
+  }
+}
+
+void ModuleSplitter::indirectCallsToSecondaryFunctions() {
+  // Update direct calls of secondary functions to be indirect calls of their
+  // corresponding table indices instead.
+  struct CallIndirector : public WalkerPass<PostWalker<CallIndirector>> {
+    ModuleSplitter& parent;
+    Builder builder;
+    CallIndirector(ModuleSplitter& parent)
+      : parent(parent), builder(parent.primary) {}
+    void visitCall(Call* curr) {
+      if (!parent.secondaryFuncs.count(curr->target)) {
+        return;
+      }
+      replaceCurrent(builder.makeCallIndirect(
+        parent.tableManager.getSlot(curr->target).makeExpr(parent.primary),
+        curr->operands,
+        parent.secondary.getFunction(curr->target)->sig,
+        curr->isReturn));
+    }
+    void visitRefFunc(RefFunc* curr) {
+      assert(false && "TODO: handle ref.func as well");
+    }
+  };
+  PassRunner runner(&primary);
+  CallIndirector(*this).run(&runner, &primary);
+}
+
+void ModuleSplitter::exportImportCalledPrimaryFunctions() {
+  // Find primary functions called in the secondary module.
+  ModuleUtils::ParallelFunctionAnalysis<std::vector<Name>> callCollector(
+    secondary, [&](Function* func, std::vector<Name>& calledPrimaryFuncs) {
+      struct CallCollector : PostWalker<CallCollector> {
+        const std::set<Name>& primaryFuncs;
+        std::vector<Name>& calledPrimaryFuncs;
+        CallCollector(const std::set<Name>& primaryFuncs,
+                      std::vector<Name>& calledPrimaryFuncs)
+          : primaryFuncs(primaryFuncs), calledPrimaryFuncs(calledPrimaryFuncs) {
+        }
+        void visitCall(Call* curr) {
+          if (primaryFuncs.count(curr->target)) {
+            calledPrimaryFuncs.push_back(curr->target);
+          }
+        }
+        void visitRefFunc(RefFunc* curr) {
+          assert(false && "TODO: handle ref.func as well");
+        }
+      };
+      CallCollector(primaryFuncs, calledPrimaryFuncs).walkFunction(func);
+    });
+  std::set<Name> calledPrimaryFuncs;
+  for (auto& entry : callCollector.map) {
+    auto& calledFuncs = entry.second;
+    calledPrimaryFuncs.insert(calledFuncs.begin(), calledFuncs.end());
+  }
+
+  // Ensure each called primary function is exported and imported
+  for (auto func : calledPrimaryFuncs) {
+    exportImportFunction(func);
+  }
+}
+
+void ModuleSplitter::setupTablePatching() {
+  std::map<Index, Name> replacedElems;
+  // Replace table references to secondary functions with an imported
+  // placeholder that encodes the table index in its name:
+  // `importNamespace`.`index`.
+  forEachElement(primary.table, [&](Name, Index index, Name& elem) {
+    if (secondaryFuncs.count(elem)) {
+      replacedElems[index] = elem;
+      auto* secondaryFunc = secondary.getFunction(elem);
+      auto placeholder = std::make_unique<Function>();
+      placeholder->module = config.placeholderNamespace;
+      placeholder->base = std::to_string(index);
+      placeholder->name = Names::getValidFunctionName(
+        primary,
+        std::string("placeholder_") + std::string(placeholder->base.c_str()));
+      placeholder->hasExplicitName = false;
+      placeholder->sig = secondaryFunc->sig;
+      elem = placeholder->name;
+      primary.addFunction(std::move(placeholder));
+    }
+  });
+
+  if (replacedElems.size() == 0) {
+    // No placeholders to patch out of the table
+    return;
+  }
+
+  if (tableManager.activeBase.global.size()) {
+    assert(primary.table.segments.size() == 1 &&
+           "Unexpected number of segments with non-const base");
+    assert(secondary.table.segments.size() == 0);
+    // Since addition is not currently allowed in initializer expressions, we
+    // need to start the new secondary segment where the primary segment starts.
+    // The secondary segment will contain the same primary functions as the
+    // primary module except in positions where it needs to overwrite a
+    // placeholder function. All primary functions in the table therefore need
+    // to be imported into the second module. TODO: use better strategies here,
+    // such as using ref.func in the start function or standardizing addition in
+    // initializer expressions.
+    const Table::Segment& primarySeg = primary.table.segments.front();
+    std::vector<Name> secondaryElems;
+    secondaryElems.reserve(primarySeg.data.size());
+
+    // Copy functions from the primary segment to the secondary segment,
+    // replacing placeholders and creating new exports and imports as necessary.
+    auto replacement = replacedElems.begin();
+    for (Index i = 0;
+         i < primarySeg.data.size() && replacement != replacedElems.end();
+         ++i) {
+      if (replacement->first == i) {
+        // primarySeg.data[i] is a placeholder, so use the secondary function.
+        secondaryElems.push_back(replacement->second);
+        ++replacement;
+      } else {
+        exportImportFunction(primarySeg.data[i]);
+        secondaryElems.push_back(primarySeg.data[i]);
+      }
+    }
+
+    auto offset = ExpressionManipulator::copy(primarySeg.offset, secondary);
+    secondary.table.segments.emplace_back(offset, secondaryElems);
+    return;
+  }
+
+  // Create active table segments in the secondary module to patch in the
+  // original functions when it is instantiated.
+  Index currBase = replacedElems.begin()->first;
+  std::vector<Name> currData;
+  auto finishSegment = [&]() {
+    auto* offset = Builder(secondary).makeConst(int32_t(currBase));
+    secondary.table.segments.emplace_back(offset, currData);
+  };
+  for (auto curr = replacedElems.begin(); curr != replacedElems.end(); ++curr) {
+    if (curr->first != currBase + currData.size()) {
+      finishSegment();
+      currBase = curr->first;
+      currData.clear();
+    }
+    currData.push_back(curr->second);
+  }
+  if (currData.size()) {
+    finishSegment();
+  }
+}
+
+void ModuleSplitter::shareImportableItems() {
+  // Map internal names to (one of) their corresponding export names. Don't
+  // consider functions because they have already been imported and exported as
+  // necessary.
+  std::unordered_map<std::pair<ExternalKind, Name>, Name> exports;
+  for (auto& ex : primary.exports) {
+    if (ex->kind != ExternalKind::Function) {
+      exports[std::make_pair(ex->kind, ex->value)] = ex->name;
+    }
+  }
+
+  auto makeImportExport = [&](Importable& primaryItem,
+                              Importable& secondaryItem,
+                              const std::string& genericExportName,
+                              ExternalKind kind) {
+    secondaryItem.name = primaryItem.name;
+    secondaryItem.hasExplicitName = primaryItem.hasExplicitName;
+    secondaryItem.module = config.importNamespace;
+    auto exportIt = exports.find(std::make_pair(kind, primaryItem.name));
+    if (exportIt != exports.end()) {
+      secondaryItem.base = exportIt->second;
+    } else {
+      Name exportName = Names::getValidExportName(
+        primary, config.newExportPrefix + genericExportName);
+      primary.addExport(new Export{exportName, primaryItem.name, kind});
+      secondaryItem.base = exportName;
+    }
+  };
+
+  // TODO: Be more selective by only sharing global items that are actually used
+  // in the secondary module, just like we do for functions.
+
+  if (primary.memory.exists) {
+    secondary.memory.exists = true;
+    secondary.memory.initial = primary.memory.initial;
+    secondary.memory.max = primary.memory.max;
+    secondary.memory.shared = primary.memory.shared;
+    secondary.memory.indexType = primary.memory.indexType;
+    makeImportExport(
+      primary.memory, secondary.memory, "memory", ExternalKind::Memory);
+  }
+
+  if (primary.table.exists) {
+    secondary.table.exists = true;
+    secondary.table.initial = primary.table.initial;
+    secondary.table.max = primary.table.max;
+    makeImportExport(
+      primary.table, secondary.table, "table", ExternalKind::Table);
+  }
+
+  for (auto& global : primary.globals) {
+    if (global->mutable_) {
+      assert(primary.features.hasMutableGlobals() &&
+             "TODO: add wrapper functions for disallowed mutable globals");
+    }
+    auto secondaryGlobal = std::make_unique<Global>();
+    secondaryGlobal->type = global->type;
+    secondaryGlobal->mutable_ = global->mutable_;
+    secondaryGlobal->init =
+      global->init == nullptr
+        ? nullptr
+        : ExpressionManipulator::copy(global->init, secondary);
+    makeImportExport(*global, *secondaryGlobal, "global", ExternalKind::Global);
+    secondary.addGlobal(std::move(secondaryGlobal));
+  }
+
+  for (auto& event : primary.events) {
+    auto secondaryEvent = std::make_unique<Event>();
+    secondaryEvent->attribute = event->attribute;
+    secondaryEvent->sig = event->sig;
+    makeImportExport(*event, *secondaryEvent, "event", ExternalKind::Event);
+    secondary.addEvent(std::move(secondaryEvent));
+  }
+}
+
+} // anonymous namespace
+
+std::unique_ptr<Module> splitFunctions(Module& primary, const Config& config) {
+  return std::move(ModuleSplitter(primary, config).secondaryPtr);
+}
+
+} // namespace ModuleSplitting
+
+} // namespace wasm
diff --git a/binaryen/src/ir/module-splitting.h b/binaryen/src/ir/module-splitting.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/ir/module-splitting.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+// module-splitting.h: Provides an interface for decomposing WebAssembly modules
+// into multiple modules that can be loaded independently. This works by moving
+// functions to a new secondary module and rewriting the primary module to call
+// them indirectly. Until the secondary module is instantiated, those indirect
+// calls will go to placeholder functions newly imported into the primary
+// module. If the primary module has a single segment with a non-constant
+// offset, the placeholder function import names are the offsets from that base
+// global of the corresponding functions in the table. Otherwise, the
+// placeholder import names are the absolute table indices of the corresponding
+// functions. The secondary module imports all of its dependencies from the
+// primary module.
+//
+// This code currently makes a few assumptions about the modules that will be
+// split and will fail assertions if those assumptions are not true.
+//
+//   1) It assumes that mutable-globals are allowed.
+//
+//   2) It assumes that either all segment offsets are constants or there is
+//      exactly one segment that may have a non-constant offset.
+//
+//   3) It assumes that each function appears in the table at most once.
+//
+// These requirements will be relaxed as necessary in the future, but for now
+// this code should be considered experimental and used with care.
+
+#ifndef wasm_ir_module_splitting_h
+#define wasm_ir_module_splitting_h
+
+#include "wasm.h"
+
+namespace wasm {
+
+namespace ModuleSplitting {
+
+struct Config {
+  // The set of functions to keep in the primary module. All others are split
+  // out into the new secondary module. Must include the start function if it
+  // exists. May or may not include imported functions, which are always kept in
+  // the primary module regardless.
+  std::set<Name> primaryFuncs;
+  // The namespace from which to import primary functions into the secondary
+  // module.
+  Name importNamespace = "primary";
+  // The namespace from which to import placeholder functions into the primary
+  // module.
+  Name placeholderNamespace = "placeholder";
+  // The prefix to attach to the name of any newly created exports. This can be
+  // used to differentiate between "real" exports of the module and exports that
+  // should only be consumed by the secondary module.
+  std::string newExportPrefix = "";
+};
+
+// Returns the new secondary module and modifies the `primary` module in place.
+std::unique_ptr<Module> splitFunctions(Module& primary, const Config& config);
+
+} // namespace ModuleSplitting
+
+} // namespace wasm
+
+#endif // wasm_ir_module_splitting_h
diff --git a/binaryen/src/ir/module-utils.h b/binaryen/src/ir/module-utils.h
--- a/binaryen/src/ir/module-utils.h
+++ b/binaryen/src/ir/module-utils.h
@@ -308,7 +308,9 @@
   struct FunctionInfo {
     std::set<Function*> callsTo;
     std::set<Function*> calledBy;
-    bool hasIndirectCall = false;
+    // A non-direct call is any call that is not direct. That includes
+    // CallIndirect and CallRef.
+    bool hasNonDirectCall = false;
   };
 
   typedef std::map<Function*, T> Map;
@@ -329,10 +331,10 @@
         void visitCall(Call* curr) {
           info.callsTo.insert(module->getFunction(curr->target));
         }
-
         void visitCallIndirect(CallIndirect* curr) {
-          info.hasIndirectCall = true;
+          info.hasNonDirectCall = true;
         }
+        void visitCallRef(CallRef* curr) { info.hasNonDirectCall = true; }
 
       private:
         Module* module;
@@ -354,7 +356,7 @@
     }
   }
 
-  enum IndirectCalls { IgnoreIndirectCalls, IndirectCallsHaveProperty };
+  enum NonDirectCalls { IgnoreNonDirectCalls, NonDirectCallsHaveProperty };
 
   // Propagate a property from a function to those that call it.
   //
@@ -365,13 +367,13 @@
   void propagateBack(std::function<bool(const T&)> hasProperty,
                      std::function<bool(const T&)> canHaveProperty,
                      std::function<void(T&, Function*)> addProperty,
-                     IndirectCalls indirectCalls) {
+                     NonDirectCalls nonDirectCalls) {
     // The work queue contains items we just learned can change the state.
     UniqueDeferredQueue<Function*> work;
     for (auto& func : wasm.functions) {
       if (hasProperty(map[func.get()]) ||
-          (indirectCalls == IndirectCallsHaveProperty &&
-           map[func.get()].hasIndirectCall)) {
+          (nonDirectCalls == NonDirectCallsHaveProperty &&
+           map[func.get()].hasNonDirectCall)) {
         addProperty(map[func.get()], func.get());
         work.push(func.get());
       }
@@ -390,19 +392,33 @@
   }
 };
 
-// Helper function for collecting the type signatures used in a module
+// Helper function for collecting all the types that are declared in a module,
+// which means the HeapTypes (that are non-basic, that is, not eqref etc., which
+// do not need to be defined).
 //
-// Used when emitting or printing a module to give signatures canonical
-// indices. Signatures are sorted in order of decreasing frequency to minize the
+// Used when emitting or printing a module to give HeapTypes canonical
+// indices. HeapTypes are sorted in order of decreasing frequency to minize the
 // size of their collective encoding. Both a vector mapping indices to
-// signatures and a map mapping signatures to indices are produced.
-inline void
-collectSignatures(Module& wasm,
-                  std::vector<Signature>& signatures,
-                  std::unordered_map<Signature, Index>& sigIndices) {
-  using Counts = std::unordered_map<Signature, size_t>;
+// HeapTypes and a map mapping HeapTypes to indices are produced.
+inline void collectHeapTypes(Module& wasm,
+                             std::vector<HeapType>& types,
+                             std::unordered_map<HeapType, Index>& typeIndices) {
+  struct Counts : public std::unordered_map<HeapType, size_t> {
+    bool isRelevant(Type type) {
+      if (type.isRef()) {
+        return !type.getHeapType().isBasic();
+      }
+      return type.isRtt();
+    }
+    void note(HeapType type) { (*this)[type]++; }
+    void maybeNote(Type type) {
+      if (isRelevant(type)) {
+        note(type.getHeapType());
+      }
+    }
+  };
 
-  // Collect the signature use counts for a single function
+  // Collect the type use counts for a single function
   auto updateCounts = [&](Function* func, Counts& counts) {
     if (func->imported()) {
       return;
@@ -412,13 +428,23 @@
       Counts& counts;
 
       TypeCounter(Counts& counts) : counts(counts) {}
+
       void visitExpression(Expression* curr) {
         if (auto* call = curr->dynCast<CallIndirect>()) {
-          counts[call->sig]++;
+          counts.note(call->sig);
+        } else if (curr->is<RefNull>()) {
+          counts.maybeNote(curr->type);
+        } else if (curr->is<RttCanon>() || curr->is<RttSub>()) {
+          counts.note(curr->type.getRtt().heapType);
+        } else if (auto* get = curr->dynCast<StructGet>()) {
+          counts.maybeNote(get->ref->type);
+        } else if (auto* set = curr->dynCast<StructSet>()) {
+          counts.maybeNote(set->ref->type);
         } else if (Properties::isControlFlowStructure(curr)) {
-          // TODO: Allow control flow to have input types as well
+          counts.maybeNote(curr->type);
           if (curr->type.isTuple()) {
-            counts[Signature(Type::none, curr->type)]++;
+            // TODO: Allow control flow to have input types as well
+            counts.note(Signature(Type::none, curr->type));
           }
         }
       }
@@ -431,29 +457,127 @@
   // Collect all the counts.
   Counts counts;
   for (auto& curr : wasm.functions) {
-    counts[curr->sig]++;
+    counts.note(curr->sig);
+    for (auto type : curr->vars) {
+      counts.maybeNote(type);
+      if (type.isTuple()) {
+        for (auto t : type) {
+          counts.maybeNote(t);
+        }
+      }
+    }
   }
   for (auto& curr : wasm.events) {
-    counts[curr->sig]++;
+    counts.note(curr->sig);
   }
+  for (auto& curr : wasm.globals) {
+    counts.maybeNote(curr->type);
+  }
   for (auto& pair : analysis.map) {
     Counts& functionCounts = pair.second;
     for (auto& innerPair : functionCounts) {
       counts[innerPair.first] += innerPair.second;
     }
   }
-  std::vector<std::pair<Signature, size_t>> sorted(counts.begin(),
-                                                   counts.end());
+  // A generic utility to traverse the child types of a type.
+  // TODO: work with tlively to refactor this to a shared place
+  auto walkRelevantChildren = [&](HeapType type,
+                                  std::function<void(HeapType)> callback) {
+    auto callIfRelevant = [&](Type type) {
+      if (counts.isRelevant(type)) {
+        callback(type.getHeapType());
+      }
+    };
+    if (type.isSignature()) {
+      auto sig = type.getSignature();
+      for (Type type : {sig.params, sig.results}) {
+        for (auto element : type) {
+          callIfRelevant(element);
+        }
+      }
+    } else if (type.isArray()) {
+      callIfRelevant(type.getArray().element.type);
+    } else if (type.isStruct()) {
+      auto fields = type.getStruct().fields;
+      for (auto field : fields) {
+        callIfRelevant(field.type);
+      }
+    }
+  };
+  // Recursively traverse each reference type, which may have a child type that
+  // is itself a reference type. This reflects an appearance in the binary
+  // format that is in the type section itself.
+  // As we do this we may find more and more types, as nested children of
+  // previous ones. Each such type will appear in the type section once, so
+  // we just need to visit it once.
+  // TODO: handle struct and array fields
+  std::unordered_set<HeapType> newTypes;
+  for (auto& pair : counts) {
+    newTypes.insert(pair.first);
+  }
+  while (!newTypes.empty()) {
+    auto iter = newTypes.begin();
+    auto type = *iter;
+    newTypes.erase(iter);
+    walkRelevantChildren(type, [&](HeapType type) {
+      if (!counts.count(type)) {
+        newTypes.insert(type);
+      }
+      counts.note(type);
+    });
+  }
+
+  // We must sort all the dependencies of a type before it. For example,
+  // (func (param (ref (func)))) must appear after (func). To do that, find the
+  // depth of dependencies of each type. For example, if A depends on B
+  // which depends on C, then A's depth is 2, B's is 1, and C's is 0 (assuming
+  // no other dependencies).
+  Counts depthOfDependencies;
+  std::unordered_map<HeapType, std::unordered_set<HeapType>> isDependencyOf;
+  // To calculate the depth of dependencies, we'll do a flow analysis, visiting
+  // each type as we find out new things about it.
+  std::set<HeapType> toVisit;
+  for (auto& pair : counts) {
+    auto type = pair.first;
+    depthOfDependencies[type] = 0;
+    toVisit.insert(type);
+    walkRelevantChildren(type, [&](HeapType childType) {
+      isDependencyOf[childType].insert(type); // XXX flip?
+    });
+  }
+  while (!toVisit.empty()) {
+    auto iter = toVisit.begin();
+    auto type = *iter;
+    toVisit.erase(iter);
+    // Anything that depends on this has a depth of dependencies equal to this
+    // type's, plus this type itself.
+    auto newDepth = depthOfDependencies[type] + 1;
+    if (newDepth > counts.size()) {
+      Fatal() << "Cyclic types detected, cannot sort them.";
+    }
+    for (auto& other : isDependencyOf[type]) {
+      if (depthOfDependencies[other] < newDepth) {
+        // We found something new to propagate.
+        depthOfDependencies[other] = newDepth;
+        toVisit.insert(other);
+      }
+    }
+  }
+  // Sort by frequency and then simplicity, and also keeping every type
+  // before things that depend on it.
+  std::vector<std::pair<HeapType, size_t>> sorted(counts.begin(), counts.end());
   std::sort(sorted.begin(), sorted.end(), [&](auto a, auto b) {
-    // order by frequency then simplicity
+    if (depthOfDependencies[a.first] != depthOfDependencies[b.first]) {
+      return depthOfDependencies[a.first] < depthOfDependencies[b.first];
+    }
     if (a.second != b.second) {
       return a.second > b.second;
     }
     return a.first < b.first;
   });
   for (Index i = 0; i < sorted.size(); ++i) {
-    sigIndices[sorted[i].first] = i;
-    signatures.push_back(sorted[i].first);
+    typeIndices[sorted[i].first] = i;
+    types.push_back(sorted[i].first);
   }
 }
 
diff --git a/binaryen/src/ir/names.h b/binaryen/src/ir/names.h
--- a/binaryen/src/ir/names.h
+++ b/binaryen/src/ir/names.h
@@ -46,6 +46,41 @@
   }
 }
 
+// Given a root of a name, finds a valid name with perhaps a number appended
+// to it, by calling a function to check if a name is valid.
+inline Name
+getValidName(Module& module, Name root, std::function<bool(Name)> check) {
+  if (check(root)) {
+    return root;
+  }
+  auto prefixed = std::string(root.str) + '_';
+  Index num = 0;
+  while (1) {
+    auto name = prefixed + std::to_string(num);
+    if (check(name)) {
+      return name;
+    }
+    num++;
+  }
+}
+
+inline Name getValidExportName(Module& module, Name root) {
+  return getValidName(
+    module, root, [&](Name test) { return !module.getExportOrNull(test); });
+}
+inline Name getValidGlobalName(Module& module, Name root) {
+  return getValidName(
+    module, root, [&](Name test) { return !module.getGlobalOrNull(test); });
+}
+inline Name getValidFunctionName(Module& module, Name root) {
+  return getValidName(
+    module, root, [&](Name test) { return !module.getFunctionOrNull(test); });
+}
+inline Name getValidEventName(Module& module, Name root) {
+  return getValidName(
+    module, root, [&](Name test) { return !module.getEventOrNull(test); });
+}
+
 } // namespace Names
 
 } // namespace wasm
diff --git a/binaryen/src/ir/properties.h b/binaryen/src/ir/properties.h
--- a/binaryen/src/ir/properties.h
+++ b/binaryen/src/ir/properties.h
@@ -19,6 +19,7 @@
 
 #include "ir/bits.h"
 #include "ir/effects.h"
+#include "ir/match.h"
 #include "wasm.h"
 
 namespace wasm {
@@ -79,6 +80,10 @@
   return false;
 }
 
+// A constant expression is something like a Const: it has a fixed value known
+// at compile time, and passes that propagate constants can try to propagate it.
+// Constant expressions are also allowed in global initializers in wasm.
+// TODO: look into adding more things here like RttCanon.
 inline bool isSingleConstantExpression(const Expression* curr) {
   return curr->is<Const>() || curr->is<RefNull>() || curr->is<RefFunc>() ||
          (curr->is<I31New>() && curr->cast<I31New>()->value->is<Const>());
@@ -105,7 +110,7 @@
   } else if (auto* n = curr->dynCast<RefNull>()) {
     return Literal(n->type);
   } else if (auto* r = curr->dynCast<RefFunc>()) {
-    return Literal(r->func);
+    return Literal(r->func, r->type);
   } else if (auto* i = curr->dynCast<I31New>()) {
     if (auto* c = i->value->dynCast<Const>()) {
       return Literal::makeI31(c->value.geti32());
@@ -131,84 +136,81 @@
 // Check if an expression is a sign-extend, and if so, returns the value
 // that is extended, otherwise nullptr
 inline Expression* getSignExtValue(Expression* curr) {
-  if (auto* outer = curr->dynCast<Binary>()) {
-    if (outer->op == ShrSInt32) {
-      if (auto* outerConst = outer->right->dynCast<Const>()) {
-        if (outerConst->value.geti32() != 0) {
-          if (auto* inner = outer->left->dynCast<Binary>()) {
-            if (inner->op == ShlInt32) {
-              if (auto* innerConst = inner->right->dynCast<Const>()) {
-                if (outerConst->value == innerConst->value) {
-                  return inner->left;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
+  // We only care about i32s here, and ignore i64s, unreachables, etc.
+  if (curr->type != Type::i32) {
+    return nullptr;
   }
+  using namespace Match;
+  int32_t leftShift = 0, rightShift = 0;
+  Expression* extended = nullptr;
+  if (matches(curr,
+              binary(ShrSInt32,
+                     binary(ShlInt32, any(&extended), i32(&leftShift)),
+                     i32(&rightShift))) &&
+      leftShift == rightShift && leftShift != 0) {
+    return extended;
+  }
   return nullptr;
 }
 
 // gets the size of the sign-extended value
 inline Index getSignExtBits(Expression* curr) {
-  return 32 - Bits::getEffectiveShifts(curr->cast<Binary>()->right);
+  assert(curr->type == Type::i32);
+  auto* rightShift = curr->cast<Binary>()->right;
+  return 32 - Bits::getEffectiveShifts(rightShift);
 }
 
 // Check if an expression is almost a sign-extend: perhaps the inner shift
 // is too large. We can split the shifts in that case, which is sometimes
 // useful (e.g. if we can remove the signext)
 inline Expression* getAlmostSignExt(Expression* curr) {
-  if (auto* outer = curr->dynCast<Binary>()) {
-    if (outer->op == ShrSInt32) {
-      if (auto* outerConst = outer->right->dynCast<Const>()) {
-        if (outerConst->value.geti32() != 0) {
-          if (auto* inner = outer->left->dynCast<Binary>()) {
-            if (inner->op == ShlInt32) {
-              if (auto* innerConst = inner->right->dynCast<Const>()) {
-                if (Bits::getEffectiveShifts(outerConst) <=
-                    Bits::getEffectiveShifts(innerConst)) {
-                  return inner->left;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
+  using namespace Match;
+  int32_t leftShift = 0, rightShift = 0;
+  Expression* extended = nullptr;
+  if (matches(curr,
+              binary(ShrSInt32,
+                     binary(ShlInt32, any(&extended), i32(&leftShift)),
+                     i32(&rightShift))) &&
+      Bits::getEffectiveShifts(rightShift, Type::i32) <=
+        Bits::getEffectiveShifts(leftShift, Type::i32) &&
+      rightShift != 0) {
+    return extended;
   }
   return nullptr;
 }
 
 // gets the size of the almost sign-extended value, as well as the
 // extra shifts, if any
-inline Index getAlmostSignExtBits(Expression* curr, Index& extraShifts) {
-  extraShifts = Bits::getEffectiveShifts(
-                  curr->cast<Binary>()->left->cast<Binary>()->right) -
-                Bits::getEffectiveShifts(curr->cast<Binary>()->right);
+inline Index getAlmostSignExtBits(Expression* curr, Index& extraLeftShifts) {
+  auto* leftShift = curr->cast<Binary>()->left->cast<Binary>()->right;
+  auto* rightShift = curr->cast<Binary>()->right;
+  extraLeftShifts =
+    Bits::getEffectiveShifts(leftShift) - Bits::getEffectiveShifts(rightShift);
   return getSignExtBits(curr);
 }
 
 // Check if an expression is a zero-extend, and if so, returns the value
 // that is extended, otherwise nullptr
 inline Expression* getZeroExtValue(Expression* curr) {
-  if (auto* binary = curr->dynCast<Binary>()) {
-    if (binary->op == AndInt32) {
-      if (auto* c = binary->right->dynCast<Const>()) {
-        if (Bits::getMaskedBits(c->value.geti32())) {
-          return binary->right;
-        }
-      }
-    }
+  // We only care about i32s here, and ignore i64s, unreachables, etc.
+  if (curr->type != Type::i32) {
+    return nullptr;
   }
+  using namespace Match;
+  int32_t mask = 0;
+  Expression* extended = nullptr;
+  if (matches(curr, binary(AndInt32, any(&extended), i32(&mask))) &&
+      Bits::getMaskedBits(mask) != 0) {
+    return extended;
+  }
   return nullptr;
 }
 
 // gets the size of the sign-extended value
 inline Index getZeroExtBits(Expression* curr) {
-  return Bits::getMaskedBits(
-    curr->cast<Binary>()->right->cast<Const>()->value.geti32());
+  assert(curr->type == Type::i32);
+  int32_t mask = curr->cast<Binary>()->right->cast<Const>()->value.geti32();
+  return Bits::getMaskedBits(mask);
 }
 
 // Returns a falling-through value, that is, it looks through a local.tee
diff --git a/binaryen/src/ir/type-updating.h b/binaryen/src/ir/type-updating.h
--- a/binaryen/src/ir/type-updating.h
+++ b/binaryen/src/ir/type-updating.h
@@ -17,6 +17,7 @@
 #ifndef wasm_ir_type_updating_h
 #define wasm_ir_type_updating_h
 
+#include "ir/branch-utils.h"
 #include "wasm-traversal.h"
 
 namespace wasm {
@@ -56,17 +57,11 @@
       if (block->name.is()) {
         blockInfos[block->name].block = block;
       }
-    } else if (auto* br = curr->dynCast<Break>()) {
-      // ensure info exists, discoverBreaks can then fill it
-      blockInfos[br->name];
-    } else if (auto* sw = curr->dynCast<Switch>()) {
-      // ensure info exists, discoverBreaks can then fill it
-      for (auto target : sw->targets) {
-        blockInfos[target];
-      }
-      blockInfos[sw->default_];
-    } else if (auto* br = curr->dynCast<BrOnExn>()) {
-      blockInfos[br->name];
+    } else {
+      BranchUtils::operateOnScopeNameUses(curr, [&](Name& name) {
+        // ensure info exists, discoverBreaks can then fill it
+        blockInfos[name];
+      });
     }
     // add a break to the info, for break and switch
     discoverBreaks(curr, +1);
@@ -147,32 +142,22 @@
     discoverBreaks(curr, parent ? +1 : -1);
   }
 
-  // adds (or removes) breaks depending on break/switch contents
-  void discoverBreaks(Expression* curr, int change) {
-    if (auto* br = curr->dynCast<Break>()) {
-      noteBreakChange(br->name, change, br->value);
-    } else if (auto* sw = curr->dynCast<Switch>()) {
-      applySwitchChanges(sw, change);
-    } else if (auto* br = curr->dynCast<BrOnExn>()) {
-      noteBreakChange(br->name, change, br->sent);
-    }
-  }
-
-  void applySwitchChanges(Switch* sw, int change) {
-    std::set<Name> seen;
-    for (auto target : sw->targets) {
-      if (seen.insert(target).second) {
-        noteBreakChange(target, change, sw->value);
-      }
-    }
-    if (seen.insert(sw->default_).second) {
-      noteBreakChange(sw->default_, change, sw->value);
+  // Applies a type change to a node, and potentially to its parents.
+  void changeType(Expression* curr, Type type) {
+    if (curr->type != type) {
+      curr->type = type;
+      propagateTypesUp(curr);
     }
   }
 
-  // note the addition of a node
-  void noteBreakChange(Name name, int change, Expression* value) {
-    noteBreakChange(name, change, value ? value->type : Type::none);
+  // adds (or removes) breaks depending on break/switch contents
+  void discoverBreaks(Expression* curr, int change) {
+    BranchUtils::operateOnScopeNameUsesAndSentTypes(
+      curr,
+      [&](Name& name, Type type) { noteBreakChange(name, change, type); });
+    // TODO: it may be faster to accumulate all changes to a set first, then
+    // call noteBreakChange on the unique values, as a switch can be quite
+    // large and have lots of repeated targets.
   }
 
   void noteBreakChange(Name name, int change, Type type) {
@@ -313,6 +298,10 @@
     if (curr->type == Type::unreachable) {
       propagateTypesUp(curr);
     }
+  }
+
+  bool hasBreaks(Block* block) {
+    return block->name.is() && blockInfos[block->name].numBreaks > 0;
   }
 };
 
diff --git a/binaryen/src/ir/utils.h b/binaryen/src/ir/utils.h
--- a/binaryen/src/ir/utils.h
+++ b/binaryen/src/ir/utils.h
@@ -111,70 +111,11 @@
 
   std::map<Name, Type> breakValues;
 
-  void visitBlock(Block* curr);
-  void visitIf(If* curr);
-  void visitLoop(Loop* curr);
-  void visitBreak(Break* curr);
-  void visitSwitch(Switch* curr);
-  void visitCall(Call* curr);
-  void visitCallIndirect(CallIndirect* curr);
-  void visitLocalGet(LocalGet* curr);
-  void visitLocalSet(LocalSet* curr);
-  void visitGlobalGet(GlobalGet* curr);
-  void visitGlobalSet(GlobalSet* curr);
-  void visitLoad(Load* curr);
-  void visitStore(Store* curr);
-  void visitAtomicRMW(AtomicRMW* curr);
-  void visitAtomicCmpxchg(AtomicCmpxchg* curr);
-  void visitAtomicWait(AtomicWait* curr);
-  void visitAtomicNotify(AtomicNotify* curr);
-  void visitAtomicFence(AtomicFence* curr);
-  void visitSIMDExtract(SIMDExtract* curr);
-  void visitSIMDReplace(SIMDReplace* curr);
-  void visitSIMDShuffle(SIMDShuffle* curr);
-  void visitSIMDTernary(SIMDTernary* curr);
-  void visitSIMDShift(SIMDShift* curr);
-  void visitSIMDLoad(SIMDLoad* curr);
-  void visitMemoryInit(MemoryInit* curr);
-  void visitDataDrop(DataDrop* curr);
-  void visitMemoryCopy(MemoryCopy* curr);
-  void visitMemoryFill(MemoryFill* curr);
-  void visitConst(Const* curr);
-  void visitUnary(Unary* curr);
-  void visitBinary(Binary* curr);
-  void visitSelect(Select* curr);
-  void visitDrop(Drop* curr);
-  void visitReturn(Return* curr);
-  void visitMemorySize(MemorySize* curr);
-  void visitMemoryGrow(MemoryGrow* curr);
-  void visitRefNull(RefNull* curr);
-  void visitRefIsNull(RefIsNull* curr);
-  void visitRefFunc(RefFunc* curr);
-  void visitRefEq(RefEq* curr);
-  void visitTry(Try* curr);
-  void visitThrow(Throw* curr);
-  void visitRethrow(Rethrow* curr);
-  void visitBrOnExn(BrOnExn* curr);
-  void visitNop(Nop* curr);
-  void visitUnreachable(Unreachable* curr);
-  void visitPop(Pop* curr);
-  void visitTupleMake(TupleMake* curr);
-  void visitTupleExtract(TupleExtract* curr);
-  void visitI31New(I31New* curr);
-  void visitI31Get(I31Get* curr);
-  void visitRefTest(RefTest* curr);
-  void visitRefCast(RefCast* curr);
-  void visitBrOnCast(BrOnCast* curr);
-  void visitRttCanon(RttCanon* curr);
-  void visitRttSub(RttSub* curr);
-  void visitStructNew(StructNew* curr);
-  void visitStructGet(StructGet* curr);
-  void visitStructSet(StructSet* curr);
-  void visitArrayNew(ArrayNew* curr);
-  void visitArrayGet(ArrayGet* curr);
-  void visitArraySet(ArraySet* curr);
-  void visitArrayLen(ArrayLen* curr);
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  void visit##CLASS_TO_VISIT(CLASS_TO_VISIT* curr);
 
+#include "wasm-delegations.h"
+
   void visitFunction(Function* curr);
 
   void visitExport(Export* curr);
@@ -195,69 +136,10 @@
 // Re-finalize a single node. This is slow, if you want to refinalize
 // an entire ast, use ReFinalize
 struct ReFinalizeNode : public OverriddenVisitor<ReFinalizeNode> {
-  void visitBlock(Block* curr) { curr->finalize(); }
-  void visitIf(If* curr) { curr->finalize(); }
-  void visitLoop(Loop* curr) { curr->finalize(); }
-  void visitBreak(Break* curr) { curr->finalize(); }
-  void visitSwitch(Switch* curr) { curr->finalize(); }
-  void visitCall(Call* curr) { curr->finalize(); }
-  void visitCallIndirect(CallIndirect* curr) { curr->finalize(); }
-  void visitLocalGet(LocalGet* curr) { curr->finalize(); }
-  void visitLocalSet(LocalSet* curr) { curr->finalize(); }
-  void visitGlobalGet(GlobalGet* curr) { curr->finalize(); }
-  void visitGlobalSet(GlobalSet* curr) { curr->finalize(); }
-  void visitLoad(Load* curr) { curr->finalize(); }
-  void visitStore(Store* curr) { curr->finalize(); }
-  void visitAtomicRMW(AtomicRMW* curr) { curr->finalize(); }
-  void visitAtomicCmpxchg(AtomicCmpxchg* curr) { curr->finalize(); }
-  void visitAtomicWait(AtomicWait* curr) { curr->finalize(); }
-  void visitAtomicNotify(AtomicNotify* curr) { curr->finalize(); }
-  void visitAtomicFence(AtomicFence* curr) { curr->finalize(); }
-  void visitSIMDExtract(SIMDExtract* curr) { curr->finalize(); }
-  void visitSIMDReplace(SIMDReplace* curr) { curr->finalize(); }
-  void visitSIMDShuffle(SIMDShuffle* curr) { curr->finalize(); }
-  void visitSIMDTernary(SIMDTernary* curr) { curr->finalize(); }
-  void visitSIMDShift(SIMDShift* curr) { curr->finalize(); }
-  void visitSIMDLoad(SIMDLoad* curr) { curr->finalize(); }
-  void visitMemoryInit(MemoryInit* curr) { curr->finalize(); }
-  void visitDataDrop(DataDrop* curr) { curr->finalize(); }
-  void visitMemoryCopy(MemoryCopy* curr) { curr->finalize(); }
-  void visitMemoryFill(MemoryFill* curr) { curr->finalize(); }
-  void visitConst(Const* curr) { curr->finalize(); }
-  void visitUnary(Unary* curr) { curr->finalize(); }
-  void visitBinary(Binary* curr) { curr->finalize(); }
-  void visitSelect(Select* curr) { curr->finalize(); }
-  void visitDrop(Drop* curr) { curr->finalize(); }
-  void visitReturn(Return* curr) { curr->finalize(); }
-  void visitMemorySize(MemorySize* curr) { curr->finalize(); }
-  void visitMemoryGrow(MemoryGrow* curr) { curr->finalize(); }
-  void visitRefNull(RefNull* curr) { curr->finalize(); }
-  void visitRefIsNull(RefIsNull* curr) { curr->finalize(); }
-  void visitRefFunc(RefFunc* curr) { curr->finalize(); }
-  void visitRefEq(RefEq* curr) { curr->finalize(); }
-  void visitTry(Try* curr) { curr->finalize(); }
-  void visitThrow(Throw* curr) { curr->finalize(); }
-  void visitRethrow(Rethrow* curr) { curr->finalize(); }
-  void visitBrOnExn(BrOnExn* curr) { curr->finalize(); }
-  void visitNop(Nop* curr) { curr->finalize(); }
-  void visitUnreachable(Unreachable* curr) { curr->finalize(); }
-  void visitPop(Pop* curr) { curr->finalize(); }
-  void visitTupleMake(TupleMake* curr) { curr->finalize(); }
-  void visitTupleExtract(TupleExtract* curr) { curr->finalize(); }
-  void visitI31New(I31New* curr) { curr->finalize(); }
-  void visitI31Get(I31Get* curr) { curr->finalize(); }
-  void visitRefTest(RefTest* curr) { curr->finalize(); }
-  void visitRefCast(RefCast* curr) { curr->finalize(); }
-  void visitBrOnCast(BrOnCast* curr) { curr->finalize(); }
-  void visitRttCanon(RttCanon* curr) { curr->finalize(); }
-  void visitRttSub(RttSub* curr) { curr->finalize(); }
-  void visitStructNew(StructNew* curr) { curr->finalize(); }
-  void visitStructGet(StructGet* curr) { curr->finalize(); }
-  void visitStructSet(StructSet* curr) { curr->finalize(); }
-  void visitArrayNew(ArrayNew* curr) { curr->finalize(); }
-  void visitArrayGet(ArrayGet* curr) { curr->finalize(); }
-  void visitArraySet(ArraySet* curr) { curr->finalize(); }
-  void visitArrayLen(ArrayLen* curr) { curr->finalize(); }
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  void visit##CLASS_TO_VISIT(CLASS_TO_VISIT* curr) { curr->finalize(); }
+
+#include "wasm-delegations.h"
 
   void visitExport(Export* curr) { WASM_UNREACHABLE("unimp"); }
   void visitGlobal(Global* curr) { WASM_UNREACHABLE("unimp"); }
diff --git a/binaryen/src/js/binaryen.js-post.js b/binaryen/src/js/binaryen.js-post.js
--- a/binaryen/src/js/binaryen.js-post.js
+++ b/binaryen/src/js/binaryen.js-post.js
@@ -9,7 +9,7 @@
 }
 
 function strToStack(str) {
-  return str ? allocate(intArrayFromString(str), 'i8', ALLOC_STACK) : 0;
+  return str ? allocate(intArrayFromString(str), ALLOC_STACK) : 0;
 }
 
 function i32sToStack(i32s) {
@@ -99,6 +99,7 @@
     'Pop',
     'I31New',
     'I31Get',
+    'CallRef',
     'RefTest',
     'RefCast',
     'BrOnCast',
@@ -415,8 +416,6 @@
     'MaxSVecI32x4',
     'MaxUVecI32x4',
     'NegVecI64x2',
-    'AnyTrueVecI64x2',
-    'AllTrueVecI64x2',
     'ShlVecI64x2',
     'ShrSVecI64x2',
     'ShrUVecI64x2',
@@ -629,6 +628,17 @@
     },
     'fill'(dest, value, size) {
       return Module['_BinaryenMemoryFill'](module, dest, value, size);
+    },
+    'atomic': {
+      'notify'(ptr, notifyCount) {
+        return Module['_BinaryenAtomicNotify'](module, ptr, notifyCount);
+      },
+      'wait32'(ptr, expected, timeout) {
+        return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i32']);
+      },
+      'wait64'(ptr, expected, timeout) {
+        return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i64']);
+      }
     }
   }
 
@@ -889,9 +899,6 @@
           return Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i32'])
         },
       },
-      'wait'(ptr, expected, timeout) {
-        return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i32']);
-      }
     },
     'pop'() {
       return Module['_BinaryenPop'](module, Module['i32']);
@@ -1193,9 +1200,6 @@
           return Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i64'])
         },
       },
-      'wait'(ptr, expected, timeout) {
-        return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i64']);
-      }
     },
     'pop'() {
       return Module['_BinaryenPop'](module, Module['i64']);
@@ -1822,12 +1826,6 @@
     'neg'(value) {
       return Module['_BinaryenUnary'](module, Module['NegVecI64x2'], value);
     },
-    'any_true'(value) {
-      return Module['_BinaryenUnary'](module, Module['AnyTrueVecI64x2'], value);
-    },
-    'all_true'(value) {
-      return Module['_BinaryenUnary'](module, Module['AllTrueVecI64x2'], value);
-    },
     'shl'(vec, shift) {
       return Module['_BinaryenSIMDShift'](module, Module['ShlVecI64x2'], vec, shift);
     },
@@ -2107,8 +2105,8 @@
     'is_null'(value) {
       return Module['_BinaryenRefIsNull'](module, value);
     },
-    'func'(func) {
-      return preserveStack(() => Module['_BinaryenRefFunc'](module, strToStack(func)));
+    'func'(func, type) {
+      return preserveStack(() => Module['_BinaryenRefFunc'](module, strToStack(func), type));
     },
     'eq'(left, right) {
       return Module['_BinaryenRefEq'](module, left, right);
@@ -2132,9 +2130,6 @@
   };
 
   self['atomic'] = {
-    'notify'(ptr, notifyCount) {
-      return Module['_BinaryenAtomicNotify'](module, ptr, notifyCount);
-    },
     'fence'() {
       return Module['_BinaryenAtomicFence'](module);
     }
@@ -2289,7 +2284,7 @@
       const segmentOffset = new Array(segmentsLen);
       for (let i = 0; i < segmentsLen; i++) {
         const { data, offset, passive } = segments[i];
-        segmentData[i] = allocate(data, 'i8', ALLOC_STACK);
+        segmentData[i] = allocate(data, ALLOC_STACK);
         segmentDataLen[i] = data.length;
         segmentPassive[i] = passive;
         segmentOffset[i] = offset;
@@ -2337,18 +2332,27 @@
       Module['_BinaryenAddCustomSection'](module, strToStack(name), i8sToStack(contents), contents.length)
     );
   };
+  self['getExport'] = function(externalName) {
+    return preserveStack(() => Module['_BinaryenGetExport'](module, strToStack(externalName)));
+  };
   self['getNumExports'] = function() {
     return Module['_BinaryenGetNumExports'](module);
-  }
-  self['getExportByIndex'] = function(id) {
-    return Module['_BinaryenGetExportByIndex'](module, id);
-  }
+  };
+  self['getExportByIndex'] = function(index) {
+    return Module['_BinaryenGetExportByIndex'](module, index);
+  };
   self['getNumFunctions'] = function() {
     return Module['_BinaryenGetNumFunctions'](module);
-  }
-  self['getFunctionByIndex'] = function(id) {
-    return Module['_BinaryenGetFunctionByIndex'](module, id);
-  }
+  };
+  self['getFunctionByIndex'] = function(index) {
+    return Module['_BinaryenGetFunctionByIndex'](module, index);
+  };
+  self['getNumGlobals'] = function() {
+    return Module['_BinaryenGetNumGlobals'](module);
+  };
+  self['getGlobalByIndex'] = function(index) {
+    return Module['_BinaryenGetGlobalByIndex'](module, index);
+  };
   self['emitText'] = function() {
     const old = out;
     let ret = '';
@@ -2990,7 +2994,7 @@
 Object.defineProperty(Module, 'readBinary', { writable: true });
 
 Module['readBinary'] = function(data) {
-  const buffer = allocate(data, 'i8', ALLOC_NORMAL);
+  const buffer = allocate(data, ALLOC_NORMAL);
   const ptr = Module['_BinaryenModuleRead'](buffer, data.length);
   _free(buffer);
   return wrapModule(ptr);
diff --git a/binaryen/src/literal.h b/binaryen/src/literal.h
--- a/binaryen/src/literal.h
+++ b/binaryen/src/literal.h
@@ -31,6 +31,10 @@
 
 class Literals;
 struct ExceptionPackage;
+struct GCData;
+// Subclass the vector type so that this is not easily confused with a vector of
+// types (which could be confusing on the Literal constructor).
+struct RttSupers : std::vector<Type> {};
 
 class Literal {
   // store only integers, whose bits are deterministic. floats
@@ -43,6 +47,24 @@
     Name func;
     // exnref package. `nullptr` indicates a `null` value.
     std::unique_ptr<ExceptionPackage> exn;
+    // A reference to GC data, either a Struct or an Array. For both of those
+    // we store the referred data as a Literals object (which is natural for an
+    // Array, and for a Struct, is just the fields in order). The type is used
+    // to indicate whether this is a Struct or an Array, and of what type.
+    std::shared_ptr<GCData> gcData;
+    // RTT values are "structural" in that the MVP doc says that multiple
+    // invocations of ref.canon return things that are observably identical, and
+    // the same is true for ref.sub. That is, what matters is the types; there
+    // is no unique identifier created in each ref.canon/sub. To track the
+    // types, we maintain a simple vector of the supertypes. Thus, an rtt.canon
+    // of type A will have an empty vector; an rtt.sub of type B of that initial
+    // canon would have a vector of size 1 containing A; a subsequent rtt.sub
+    // would have A, B, and so forth.
+    // (This encoding is very inefficient and not at all what a production VM
+    // would do, but it is simple.)
+    // The unique_ptr here is to avoid increasing the size of the union as well
+    // as the Literal class itself.
+    std::unique_ptr<RttSupers> rttSupers;
     // TODO: Literals of type `externref` can only be `null` currently but we
     // will need to represent extern values eventually, to
     // 1) run the spec tests and fuzzer with reference types enabled and
@@ -55,7 +77,7 @@
 
   Literal() : v128(), type(Type::none) {}
   explicit Literal(Type type);
-  explicit Literal(Type::BasicID typeId) : Literal(Type(typeId)) {}
+  explicit Literal(Type::BasicType type) : Literal(Type(type)) {}
   explicit Literal(int32_t init) : i32(init), type(Type::i32) {}
   explicit Literal(uint32_t init) : i32(init), type(Type::i32) {}
   explicit Literal(int64_t init) : i64(init), type(Type::i64) {}
@@ -71,16 +93,14 @@
   explicit Literal(const std::array<Literal, 8>&);
   explicit Literal(const std::array<Literal, 4>&);
   explicit Literal(const std::array<Literal, 2>&);
-  explicit Literal(Name func) : func(func), type(Type::funcref) {}
+  explicit Literal(Name func, Type type) : func(func), type(type) {}
   explicit Literal(std::unique_ptr<ExceptionPackage>&& exn)
     : exn(std::move(exn)), type(Type::exnref) {}
+  explicit Literal(std::shared_ptr<GCData> gcData, Type type);
+  explicit Literal(std::unique_ptr<RttSupers>&& rttSupers, Type type);
   Literal(const Literal& other);
   Literal& operator=(const Literal& other);
-  ~Literal() {
-    if (type.isException()) {
-      exn.~unique_ptr();
-    }
-  }
+  ~Literal();
 
   bool isConcrete() const { return type != Type::none; }
   bool isNone() const { return type == Type::none; }
@@ -92,6 +112,9 @@
       if (type.isException()) {
         return !exn;
       }
+      if (isGCData()) {
+        return !gcData;
+      }
       return true;
     }
     return false;
@@ -114,6 +137,18 @@
         WASM_UNREACHABLE("unexpected type");
     }
   }
+  bool isNegative() const {
+    switch (type.getBasic()) {
+      case Type::i32:
+      case Type::f32:
+        return i32 < 0;
+      case Type::i64:
+      case Type::f64:
+        return i64 < 0;
+      default:
+        WASM_UNREACHABLE("unexpected type");
+    }
+  }
   bool isSignedMin() const {
     switch (type.getBasic()) {
       case Type::i32:
@@ -144,6 +179,7 @@
         WASM_UNREACHABLE("unexpected type");
     }
   }
+  bool isGCData() const { return type.isStruct() || type.isArray(); }
 
   static Literals makeZeros(Type type);
   static Literals makeOnes(Type type);
@@ -221,7 +257,9 @@
     assert(type.isNullable());
     return Literal(type);
   }
-  static Literal makeFunc(Name func) { return Literal(func.c_str()); }
+  static Literal makeFunc(Name func, Type type = Type::funcref) {
+    return Literal(func, type);
+  }
   static Literal makeExn(std::unique_ptr<ExceptionPackage>&& exn) {
     return Literal(std::move(exn));
   }
@@ -262,6 +300,8 @@
     return func;
   }
   ExceptionPackage getExceptionPackage() const;
+  std::shared_ptr<GCData> getGCData() const;
+  const RttSupers& getRttSupers() const;
 
   // careful!
   int32_t* geti32Ptr() {
@@ -451,6 +491,7 @@
   Literal leUI32x4(const Literal& other) const;
   Literal geSI32x4(const Literal& other) const;
   Literal geUI32x4(const Literal& other) const;
+  Literal eqI64x2(const Literal& other) const;
   Literal eqF32x4(const Literal& other) const;
   Literal neF32x4(const Literal& other) const;
   Literal ltF32x4(const Literal& other) const;
@@ -488,6 +529,7 @@
   Literal maxSI8x16(const Literal& other) const;
   Literal maxUI8x16(const Literal& other) const;
   Literal avgrUI8x16(const Literal& other) const;
+  Literal popcntI8x16() const;
   Literal absI16x8() const;
   Literal negI16x8() const;
   Literal anyTrueI16x8() const;
@@ -508,6 +550,11 @@
   Literal maxSI16x8(const Literal& other) const;
   Literal maxUI16x8(const Literal& other) const;
   Literal avgrUI16x8(const Literal& other) const;
+  Literal q15MulrSatSI16x8(const Literal& other) const;
+  Literal extMulLowSI16x8(const Literal& other) const;
+  Literal extMulHighSI16x8(const Literal& other) const;
+  Literal extMulLowUI16x8(const Literal& other) const;
+  Literal extMulHighUI16x8(const Literal& other) const;
   Literal absI32x4() const;
   Literal negI32x4() const;
   Literal anyTrueI32x4() const;
@@ -524,15 +571,21 @@
   Literal maxSI32x4(const Literal& other) const;
   Literal maxUI32x4(const Literal& other) const;
   Literal dotSI16x8toI32x4(const Literal& other) const;
+  Literal extMulLowSI32x4(const Literal& other) const;
+  Literal extMulHighSI32x4(const Literal& other) const;
+  Literal extMulLowUI32x4(const Literal& other) const;
+  Literal extMulHighUI32x4(const Literal& other) const;
   Literal negI64x2() const;
-  Literal anyTrueI64x2() const;
-  Literal allTrueI64x2() const;
   Literal shlI64x2(const Literal& other) const;
   Literal shrSI64x2(const Literal& other) const;
   Literal shrUI64x2(const Literal& other) const;
   Literal addI64x2(const Literal& other) const;
   Literal subI64x2(const Literal& other) const;
   Literal mulI64x2(const Literal& other) const;
+  Literal extMulLowSI64x2(const Literal& other) const;
+  Literal extMulHighSI64x2(const Literal& other) const;
+  Literal extMulLowUI64x2(const Literal& other) const;
+  Literal extMulHighUI64x2(const Literal& other) const;
   Literal absF32x4() const;
   Literal negF32x4() const;
   Literal sqrtF32x4() const;
@@ -585,6 +638,11 @@
   Literal widenHighUToVecI32x4() const;
   Literal swizzleVec8x16(const Literal& other) const;
 
+  // Checks if an RTT value is a sub-rtt of another, that is, whether GC data
+  // with this object's RTT can be successfuly cast using the other RTT
+  // according to the wasm rules for that.
+  bool isSubRtt(const Literal& other) const;
+
 private:
   Literal addSatSI8(const Literal& other) const;
   Literal addSatUI8(const Literal& other) const;
@@ -611,7 +669,9 @@
       assert(lit.isConcrete());
     }
 #endif
-  };
+  }
+  Literals(size_t initialSize) : SmallVector(initialSize) {}
+
   Type getType() {
     std::vector<Type> types;
     for (auto& val : *this) {
@@ -640,6 +700,14 @@
 std::ostream& operator<<(std::ostream& o, wasm::Literals literals);
 std::ostream& operator<<(std::ostream& o, const ExceptionPackage& exn);
 
+// A GC Struct or Array is a set of values with a run-time type saying what it
+// is.
+struct GCData {
+  Literal rtt;
+  Literals values;
+  GCData(Literal rtt, Literals values) : rtt(rtt), values(values) {}
+};
+
 } // namespace wasm
 
 namespace std {
@@ -702,7 +770,12 @@
     } else if (a.type.isRef()) {
       return hashRef();
     } else if (a.type.isRtt()) {
-      WASM_UNREACHABLE("TODO: rtt literals");
+      const auto& supers = a.getRttSupers();
+      wasm::rehash(digest, supers.size());
+      for (auto super : supers) {
+        wasm::rehash(digest, super.getID());
+      }
+      return digest;
     }
     WASM_UNREACHABLE("unexpected type");
   }
diff --git a/binaryen/src/parsing.h b/binaryen/src/parsing.h
--- a/binaryen/src/parsing.h
+++ b/binaryen/src/parsing.h
@@ -22,12 +22,11 @@
 #include <sstream>
 #include <string>
 
-#include "asmjs/shared-constants.h"
 #include "mixed_arena.h"
 #include "shared-constants.h"
 #include "support/colors.h"
 #include "support/utilities.h"
-#include "wasm-printing.h"
+#include "wasm-traversal.h"
 #include "wasm.h"
 
 namespace wasm {
diff --git a/binaryen/src/pass.h b/binaryen/src/pass.h
--- a/binaryen/src/pass.h
+++ b/binaryen/src/pass.h
@@ -69,14 +69,15 @@
   // More generally, with 2 items we may have a local.get, but no way to
   // require it to be saved instead of directly consumed.
   Index alwaysInlineMaxSize = 2;
-  // Function size which we inline when functions are lightweight (no loops
-  // and calls) and we are doing aggressive optimisation for speed (-O3).
-  // In particular it's nice that with this limit we can inline the clamp
-  // functions (i32s-div, f64-to-int, etc.), that can affect perf.
-  Index flexibleInlineMaxSize = 20;
   // Function size which we inline when there is only one caller.
   // FIXME: this should logically be higher than flexibleInlineMaxSize.
   Index oneCallerInlineMaxSize = 15;
+  // Function size above which we never inline, ignoring the various flexible
+  // factors (like whether we are optimizing for size or speed) that could
+  // influence us.
+  // This is checked after alwaysInlineMaxSize and oneCallerInlineMaxSize, but
+  // the order normally won't matter.
+  Index flexibleInlineMaxSize = 20;
   // Loops usually mean the function does heavy work, so the call overhead
   // is not significant and we do not inline such functions by default.
   bool allowFunctionsWithLoops = false;
@@ -107,6 +108,15 @@
   // forth (which IEEE floats do not, strictly speaking). This is inspired by
   // gcc/clang's -ffast-math flag.
   bool fastMath = false;
+  // Whether to assume that an imported memory is zero-initialized. Without
+  // this, we can do fewer optimizations on memory segments, because if memory
+  // *was* modified then the wasm's segments may trample those previous
+  // modifications. If memory was zero-initialized then we can remove zeros from
+  // the wasm's segments.
+  // (This is not a problem if the memory is *not* imported, since then wasm
+  // creates it and we know it is all zeros right before the active segments are
+  // applied.)
+  bool zeroFilledMemory = false;
   // Whether to try to preserve debug info through, which are special calls.
   bool debugInfo = false;
   // Arbitrary string arguments from the commandline, which we forward to
@@ -226,9 +236,11 @@
   //                     doesn't help anyhow and also is bad for e.g. printing
   //                     which is a pass)
   // this method returns whether we are in passDebug mode, and which value:
-  //  1: run pass by pass, validating in between
-  //  2: also save the last pass, so it breakage happens we can print the last
-  //  one 3: also dump out byn-* files for each pass
+  //  1: log out each pass that we run, and validate in between (can pass
+  //     --no-validation to skip validation).
+  //  2: like 1, and also save the last pass's output, so if breakage happens we
+  //     can print a useful error. also logs out names of nested passes.
+  //  3: like 1, and also dumps out byn-* files for each pass as it is run.
   static int getPassDebug();
 
 protected:
@@ -255,10 +267,6 @@
 class Pass {
 public:
   virtual ~Pass() = default;
-
-  // Override this to perform preparation work before the pass runs.
-  // This will be called before the pass is run on a module.
-  virtual void prepareToRun(PassRunner* runner, Module* module) {}
 
   // Implement this with code to run the pass on the whole module
   virtual void run(PassRunner* runner, Module* module) {
diff --git a/binaryen/src/passes/Asyncify.cpp b/binaryen/src/passes/Asyncify.cpp
--- a/binaryen/src/passes/Asyncify.cpp
+++ b/binaryen/src/passes/Asyncify.cpp
@@ -677,7 +677,7 @@
                             }
                             info.canChangeState = true;
                           },
-                          scanner.IgnoreIndirectCalls);
+                          scanner.IgnoreNonDirectCalls);
 
     map.swap(scanner.map);
 
@@ -1408,8 +1408,10 @@
     bool allImportsCanChangeState =
       stateChangingImports == "" && ignoreImports == "";
     String::Split listedImports(stateChangingImports, ",");
-    auto ignoreIndirect = runner->options.getArgumentOrDefault(
-                            "asyncify-ignore-indirect", "") == "";
+    // TODO: consider renaming asyncify-ignore-indirect to
+    //       asyncify-ignore-nondirect, but that could break users.
+    auto ignoreNonDirect = runner->options.getArgumentOrDefault(
+                             "asyncify-ignore-indirect", "") == "";
     std::string removeListInput =
       runner->options.getArgumentOrDefault("asyncify-removelist", "");
     if (removeListInput.empty()) {
@@ -1462,7 +1464,7 @@
     // Scan the module.
     ModuleAnalyzer analyzer(*module,
                             canImportChangeState,
-                            ignoreIndirect,
+                            ignoreNonDirect,
                             removeList,
                             addList,
                             onlyList,
@@ -1488,6 +1490,7 @@
         // because the flow changes add many branches, break up if-elses, etc.,
         // all of which extend the live ranges of locals. In other words, it is
         // not possible to coalesce well afterwards.
+        runner.add("remove-unused-names");
         runner.add("simplify-locals-nonesting");
         runner.add("reorder-locals");
         runner.add("coalesce-locals");
@@ -1569,9 +1572,9 @@
         builder.makeIf(builder.makeBinary(GtUInt32, stackPos, stackEnd),
                        builder.makeUnreachable()));
       body->finalize();
-      auto* func = builder.makeFunction(
+      auto func = builder.makeFunction(
         name, Signature(Type(params), Type::none), {}, body);
-      module->addFunction(func);
+      module->addFunction(std::move(func));
       module->addExport(builder.makeExport(name, name, ExternalKind::Function));
     };
 
diff --git a/binaryen/src/passes/CMakeLists.txt b/binaryen/src/passes/CMakeLists.txt
--- a/binaryen/src/passes/CMakeLists.txt
+++ b/binaryen/src/passes/CMakeLists.txt
@@ -25,7 +25,6 @@
   DuplicateImportElimination.cpp
   DuplicateFunctionElimination.cpp
   DWARF.cpp
-  EmscriptenPIC.cpp
   ExtractFunction.cpp
   Flatten.cpp
   FuncCastEmulation.cpp
@@ -39,6 +38,7 @@
   LocalCSE.cpp
   LogExecution.cpp
   LoopInvariantCodeMotion.cpp
+  Memory64Lowering.cpp
   MemoryPacking.cpp
   MergeBlocks.cpp
   MergeLocals.cpp
@@ -64,7 +64,6 @@
   RemoveImports.cpp
   RemoveMemory.cpp
   RemoveNonJSOps.cpp
-  ReplaceStackPointer.cpp
   RemoveUnusedBrs.cpp
   RemoveUnusedNames.cpp
   RemoveUnusedModuleElements.cpp
@@ -76,7 +75,6 @@
   SimplifyGlobals.cpp
   SimplifyLocals.cpp
   Souperify.cpp
-  SpillPointers.cpp
   StackCheck.cpp
   SSAify.cpp
   Untee.cpp
diff --git a/binaryen/src/passes/CodePushing.cpp b/binaryen/src/passes/CodePushing.cpp
--- a/binaryen/src/passes/CodePushing.cpp
+++ b/binaryen/src/passes/CodePushing.cpp
@@ -160,7 +160,7 @@
            firstPushable < pushPoint);
     // everything that matters if you want to be pushed past the pushPoint
     EffectAnalyzer cumulativeEffects(passOptions, features);
-    cumulativeEffects.analyze(list[pushPoint]);
+    cumulativeEffects.walk(list[pushPoint]);
     // it is ok to ignore the branching here, that is the crucial point of this
     // opt
     // TODO: it would be ok to ignore thrown exceptions here, if we know they
@@ -194,7 +194,7 @@
         }
       } else {
         // something that can't be pushed, so it might block further pushing
-        cumulativeEffects.analyze(list[i]);
+        cumulativeEffects.walk(list[i]);
       }
       assert(i > 0);
       i--;
diff --git a/binaryen/src/passes/DeadArgumentElimination.cpp b/binaryen/src/passes/DeadArgumentElimination.cpp
--- a/binaryen/src/passes/DeadArgumentElimination.cpp
+++ b/binaryen/src/passes/DeadArgumentElimination.cpp
@@ -72,7 +72,11 @@
   // see inhibits our optimizations, but TODO: an export
   // could be worked around by exporting a thunk that
   // adds the parameter.
-  bool hasUnseenCalls = false;
+  // This is atomic so that we can write to it from any function at any time
+  // during the parallel analysis phase which is run in DAEScanner.
+  std::atomic<bool> hasUnseenCalls;
+
+  DAEFunctionInfo() { hasUnseenCalls = false; }
 };
 
 typedef std::unordered_map<Name, DAEFunctionInfo> DAEFunctionInfoMap;
@@ -139,12 +143,29 @@
     }
   }
 
+  void visitCallRef(CallRef* curr) {
+    if (curr->isReturn) {
+      info->hasTailCalls = true;
+    }
+  }
+
   void visitDrop(Drop* curr) {
     if (auto* call = curr->value->dynCast<Call>()) {
       info->droppedCalls[call] = getCurrentPointer();
     }
   }
 
+  void visitRefFunc(RefFunc* curr) {
+    // We can't modify another function in parallel.
+    assert((*infoMap).count(curr->func));
+    // Treat a ref.func as an unseen call, preventing us from changing the
+    // function's type. If we did change it, it could be an observable
+    // difference from the outside, if the reference escapes, for example.
+    // TODO: look for actual escaping?
+    // TODO: create a thunk for external uses that allow internal optimizations
+    (*infoMap)[curr->func].hasUnseenCalls = true;
+  }
+
   // main entry point
 
   void doWalkFunction(Function* func) {
@@ -152,14 +173,22 @@
     info = &((*infoMap)[func->name]);
     CFGWalker<DAEScanner, Visitor<DAEScanner>, DAEBlockInfo>::doWalkFunction(
       func);
-    // If there are relevant params, check if they are used. (If
-    // we can't optimize the function anyhow, there's no point.)
+    // If there are relevant params, check if they are used. If we can't
+    // optimize the function anyhow, there's no point (note that our check here
+    // is technically racy - another thread could update hasUnseenCalls to true
+    // around when we check it - but that just means that we might or might not
+    // do some extra work, as we'll ignore the results later if we have unseen
+    // calls. That is, the check for hasUnseenCalls here is just a minor
+    // optimization to avoid pointless work. We can avoid that work if either
+    // we know there is an unseen call before the parallel analysis that we are
+    // part of, say if we are exported, or if another parallel function finds a
+    // RefFunc to us and updates it before we check it).
     if (numParams > 0 && !info->hasUnseenCalls) {
-      findUnusedParams(func);
+      findUnusedParams();
     }
   }
 
-  void findUnusedParams(Function* func) {
+  void findUnusedParams() {
     // Flow the incoming parameter values, see if they reach a read.
     // Once we've seen a parameter at a block, we need never consider it there
     // again.
@@ -242,8 +271,9 @@
     DAEFunctionInfoMap infoMap;
     // Ensure they all exist so the parallel threads don't modify the data
     // structure.
-    ModuleUtils::iterDefinedFunctions(
-      *module, [&](Function* func) { infoMap[func->name]; });
+    for (auto& func : module->functions) {
+      infoMap[func->name];
+    }
     // Check the influence of the table and exports.
     for (auto& curr : module->exports) {
       if (curr->kind == ExternalKind::Function) {
@@ -326,6 +356,9 @@
     for (auto& pair : allCalls) {
       auto name = pair.first;
       auto& calls = pair.second;
+      if (infoMap[name].hasUnseenCalls) {
+        continue;
+      }
       auto* func = module->getFunction(name);
       auto numParams = func->getNumParams();
       if (numParams == 0) {
diff --git a/binaryen/src/passes/DeadCodeElimination.cpp b/binaryen/src/passes/DeadCodeElimination.cpp
--- a/binaryen/src/passes/DeadCodeElimination.cpp
+++ b/binaryen/src/passes/DeadCodeElimination.cpp
@@ -28,8 +28,8 @@
 // have no side effects.
 //
 
-#include <ir/block-utils.h>
-#include <ir/branch-utils.h>
+#include <ir/iteration.h>
+#include <ir/properties.h>
 #include <ir/type-updating.h>
 #include <pass.h>
 #include <vector>
@@ -39,7 +39,9 @@
 namespace wasm {
 
 struct DeadCodeElimination
-  : public WalkerPass<PostWalker<DeadCodeElimination>> {
+  : public WalkerPass<
+      PostWalker<DeadCodeElimination,
+                 UnifiedExpressionVisitor<DeadCodeElimination>>> {
   bool isFunctionParallel() override { return true; }
 
   Pass* create() override { return new DeadCodeElimination; }
@@ -58,514 +60,116 @@
     return expression;
   }
 
-  // whether the current code is actually reachable
-  bool reachable;
-
   void doWalkFunction(Function* func) {
-    reachable = true;
     typeUpdater.walk(func->body);
     walk(func->body);
   }
 
-  std::set<Name> reachableBreaks;
-
-  void addBreak(Name name) {
-    // we normally have already reduced unreachable code into (unreachable)
-    // nodes, so we would not get to this place at all anyhow, the breaking
-    // instruction itself would be removed. However, an exception are things
-    // like  (block (result i32) (call $x) (unreachable)) , which has type i32
-    // despite not being exited.
-    // TODO: optimize such cases
-    if (reachable) {
-      reachableBreaks.insert(name);
-    }
-  }
-
-  // if a child exists and is unreachable, we can replace ourselves with it
-  bool isDead(Expression* child) {
-    return child && child->type == Type::unreachable;
-  }
-
-  // a similar check, assumes the child exists
-  bool isUnreachable(Expression* child) {
-    return child->type == Type::unreachable;
-  }
-
-  // things that stop control flow
-
-  void visitBreak(Break* curr) {
-    if (isDead(curr->value)) {
-      // the condition is evaluated last, so if the value was unreachable, the
-      // whole thing is
-      replaceCurrent(curr->value);
-      return;
-    }
-    if (isDead(curr->condition)) {
-      if (curr->value) {
-        auto* block = getModule()->allocator.alloc<Block>();
-        block->list.resize(2);
-        block->list[0] = drop(curr->value);
-        block->list[1] = curr->condition;
-        // if we previously returned a value, then this block
-        // must have the same type, so it fits in the ast
-        // properly. it ends in an unreachable
-        // anyhow, so that is ok.
-        block->finalize(curr->type);
-        replaceCurrent(block);
-      } else {
-        replaceCurrent(curr->condition);
-      }
-      return;
-    }
-    addBreak(curr->name);
-    if (!curr->condition) {
-      reachable = false;
-    }
-  }
-
-  void visitSwitch(Switch* curr) {
-    if (isDead(curr->value)) {
-      replaceCurrent(curr->value);
-      return;
-    }
-    if (isUnreachable(curr->condition)) {
-      if (curr->value) {
-        auto* block = getModule()->allocator.alloc<Block>();
-        block->list.resize(2);
-        block->list[0] = drop(curr->value);
-        block->list[1] = curr->condition;
-        block->finalize(curr->type);
-        replaceCurrent(block);
-      } else {
-        replaceCurrent(curr->condition);
+  void visitExpression(Expression* curr) {
+    if (!Properties::isControlFlowStructure(curr)) {
+      // Control flow structures require special handling, but others are
+      // simple.
+      if (curr->type == Type::unreachable) {
+        // This may be dead code. Check if there is an unreachable child.
+        bool hasUnreachableChild = false;
+        for (auto* child : ChildIterator(curr)) {
+          if (child->type == Type::unreachable) {
+            hasUnreachableChild = true;
+            break;
+          }
+        }
+        if (hasUnreachableChild) {
+          // This is indeed unreachable code, made unreachable by that child.
+          Builder builder(*getModule());
+          std::vector<Expression*> remainingChildren;
+          bool afterUnreachable = false;
+          for (auto* child : ChildIterator(curr)) {
+            if (afterUnreachable) {
+              typeUpdater.noteRecursiveRemoval(child);
+              continue;
+            }
+            if (child->type == Type::unreachable) {
+              remainingChildren.push_back(child);
+              afterUnreachable = true;
+            } else {
+              remainingChildren.push_back(builder.makeDrop(child));
+            }
+          }
+          if (remainingChildren.size() == 1) {
+            replaceCurrent(remainingChildren[0]);
+          } else {
+            replaceCurrent(builder.makeBlock(remainingChildren));
+          }
+        }
       }
       return;
     }
-    for (auto target : curr->targets) {
-      addBreak(target);
-    }
-    addBreak(curr->default_);
-    reachable = false;
-  }
-
-  void visitReturn(Return* curr) {
-    if (isDead(curr->value)) {
-      replaceCurrent(curr->value);
-      return;
-    }
-    reachable = false;
-  }
-
-  void visitUnreachable(Unreachable* curr) { reachable = false; }
-
-  void visitBlock(Block* curr) {
-    auto& list = curr->list;
-    // if we are currently unreachable (before we take into account
-    // breaks to the block) then a child may be unreachable, and we
-    // can shorten
-    if (!reachable && list.size() > 1) {
-      // to do here: nothing to remove after it)
-      for (Index i = 0; i < list.size() - 1; i++) {
+    // This is a control flow structure.
+    if (auto* block = curr->dynCast<Block>()) {
+      auto& list = block->list;
+      // The index from which to remove, which is one after the first
+      // unreachable instruction. Note that 0 is not a valid value, so we can
+      // use it as such.
+      Index removeFromHere = 0;
+      for (Index i = 0; i < list.size(); i++) {
         if (list[i]->type == Type::unreachable) {
-          list.resize(i + 1);
+          removeFromHere = i + 1;
           break;
         }
       }
-    }
-    if (curr->name.is()) {
-      reachable = reachable || reachableBreaks.count(curr->name);
-      reachableBreaks.erase(curr->name);
-    }
-    if (list.size() == 1 && isUnreachable(list[0])) {
-      replaceCurrent(
-        BlockUtils::simplifyToContentsWithPossibleTypeChange(curr, this));
-    } else {
-      // the block may have had a type, but can now be unreachable, which allows
-      // more reduction outside
-      typeUpdater.maybeUpdateTypeToUnreachable(curr);
-    }
-  }
-
-  void visitLoop(Loop* curr) {
-    if (curr->name.is()) {
-      reachableBreaks.erase(curr->name);
-    }
-    if (isUnreachable(curr->body) &&
-        !BranchUtils::BranchSeeker::has(curr->body, curr->name)) {
-      replaceCurrent(curr->body);
-      return;
-    }
-  }
-
-  // ifs and trys need special handling: only one of (if body and else body /
-  // try body and catch body) should be reachable to make the whole of (if /
-  // try) to be reachable.
-
-  // stack of reachable state, for forking and joining
-  std::vector<bool> ifStack;
-  std::vector<bool> tryStack;
-
-  static void doAfterIfCondition(DeadCodeElimination* self,
-                                 Expression** currp) {
-    self->ifStack.push_back(self->reachable);
-  }
-
-  static void doAfterIfElseTrue(DeadCodeElimination* self, Expression** currp) {
-    assert((*currp)->cast<If>()->ifFalse);
-    bool reachableBefore = self->ifStack.back();
-    self->ifStack.pop_back();
-    self->ifStack.push_back(self->reachable);
-    self->reachable = reachableBefore;
-  }
-
-  void visitIf(If* curr) {
-    // the ifStack has the branch that joins us, either from before if just an
-    // if, or the ifTrue if an if-else
-    reachable = reachable || ifStack.back();
-    ifStack.pop_back();
-    if (isUnreachable(curr->condition)) {
-      replaceCurrent(curr->condition);
-    }
-    // the if may have had a type, but can now be unreachable, which allows more
-    // reduction outside
-    typeUpdater.maybeUpdateTypeToUnreachable(curr);
-  }
-
-  static void doBeforeTryBody(DeadCodeElimination* self, Expression** currp) {
-    self->tryStack.push_back(self->reachable);
-  }
-
-  static void doAfterTryBody(DeadCodeElimination* self, Expression** currp) {
-    bool reachableBefore = self->tryStack.back();
-    self->tryStack.pop_back();
-    self->tryStack.push_back(self->reachable);
-    self->reachable = reachableBefore;
-  }
-
-  void visitTry(Try* curr) {
-    // the tryStack has the branch that joins us
-    reachable = reachable || tryStack.back();
-    tryStack.pop_back();
-    // the try may have had a type, but can now be unreachable, which allows
-    // more reduction outside
-    typeUpdater.maybeUpdateTypeToUnreachable(curr);
-  }
-
-  void visitThrow(Throw* curr) { reachable = false; }
-
-  void visitRethrow(Rethrow* curr) { reachable = false; }
-
-  void visitBrOnExn(BrOnExn* curr) {
-    if (isDead(curr->exnref)) {
-      replaceCurrent(curr->exnref);
-      return;
-    }
-    addBreak(curr->name);
-  }
-
-  static void scan(DeadCodeElimination* self, Expression** currp) {
-    auto* curr = *currp;
-    if (!self->reachable) {
-// convert to an unreachable safely
-#define DELEGATE(CLASS_TO_VISIT)                                               \
-  {                                                                            \
-    auto* parent = self->typeUpdater.parents[curr];                            \
-    self->typeUpdater.noteRecursiveRemoval(curr);                              \
-    ExpressionManipulator::convert<CLASS_TO_VISIT, Unreachable>(               \
-      static_cast<CLASS_TO_VISIT*>(curr));                                     \
-    self->typeUpdater.noteAddition(curr, parent);                              \
-    break;                                                                     \
-  }
-      switch (curr->_id) {
-        case Expression::Id::BlockId:
-          DELEGATE(Block);
-        case Expression::Id::IfId:
-          DELEGATE(If);
-        case Expression::Id::LoopId:
-          DELEGATE(Loop);
-        case Expression::Id::BreakId:
-          DELEGATE(Break);
-        case Expression::Id::SwitchId:
-          DELEGATE(Switch);
-        case Expression::Id::CallId:
-          DELEGATE(Call);
-        case Expression::Id::CallIndirectId:
-          DELEGATE(CallIndirect);
-        case Expression::Id::LocalGetId:
-          DELEGATE(LocalGet);
-        case Expression::Id::LocalSetId:
-          DELEGATE(LocalSet);
-        case Expression::Id::GlobalGetId:
-          DELEGATE(GlobalGet);
-        case Expression::Id::GlobalSetId:
-          DELEGATE(GlobalSet);
-        case Expression::Id::LoadId:
-          DELEGATE(Load);
-        case Expression::Id::StoreId:
-          DELEGATE(Store);
-        case Expression::Id::ConstId:
-          DELEGATE(Const);
-        case Expression::Id::UnaryId:
-          DELEGATE(Unary);
-        case Expression::Id::BinaryId:
-          DELEGATE(Binary);
-        case Expression::Id::SelectId:
-          DELEGATE(Select);
-        case Expression::Id::DropId:
-          DELEGATE(Drop);
-        case Expression::Id::ReturnId:
-          DELEGATE(Return);
-        case Expression::Id::MemorySizeId:
-          DELEGATE(MemorySize);
-        case Expression::Id::MemoryGrowId:
-          DELEGATE(MemoryGrow);
-        case Expression::Id::NopId:
-          DELEGATE(Nop);
-        case Expression::Id::UnreachableId:
-          break;
-        case Expression::Id::AtomicCmpxchgId:
-          DELEGATE(AtomicCmpxchg);
-        case Expression::Id::AtomicRMWId:
-          DELEGATE(AtomicRMW);
-        case Expression::Id::AtomicWaitId:
-          DELEGATE(AtomicWait);
-        case Expression::Id::AtomicNotifyId:
-          DELEGATE(AtomicNotify);
-        case Expression::Id::AtomicFenceId:
-          DELEGATE(AtomicFence);
-        case Expression::Id::SIMDExtractId:
-          DELEGATE(SIMDExtract);
-        case Expression::Id::SIMDReplaceId:
-          DELEGATE(SIMDReplace);
-        case Expression::Id::SIMDShuffleId:
-          DELEGATE(SIMDShuffle);
-        case Expression::Id::SIMDTernaryId:
-          DELEGATE(SIMDTernary);
-        case Expression::Id::SIMDShiftId:
-          DELEGATE(SIMDShift);
-        case Expression::Id::SIMDLoadId:
-          DELEGATE(SIMDLoad);
-        case Expression::Id::MemoryInitId:
-          DELEGATE(MemoryInit);
-        case Expression::Id::DataDropId:
-          DELEGATE(DataDrop);
-        case Expression::Id::MemoryCopyId:
-          DELEGATE(MemoryCopy);
-        case Expression::Id::MemoryFillId:
-          DELEGATE(MemoryFill);
-        case Expression::Id::PopId:
-          DELEGATE(Pop);
-        case Expression::Id::RefNullId:
-          DELEGATE(RefNull);
-        case Expression::Id::RefIsNullId:
-          DELEGATE(RefIsNull);
-        case Expression::Id::RefFuncId:
-          DELEGATE(RefFunc);
-        case Expression::Id::RefEqId:
-          DELEGATE(RefEq);
-        case Expression::Id::TryId:
-          DELEGATE(Try);
-        case Expression::Id::ThrowId:
-          DELEGATE(Throw);
-        case Expression::Id::RethrowId:
-          DELEGATE(Rethrow);
-        case Expression::Id::BrOnExnId:
-          DELEGATE(BrOnExn);
-        case Expression::Id::TupleMakeId:
-          DELEGATE(TupleMake);
-        case Expression::Id::TupleExtractId:
-          DELEGATE(TupleExtract);
-        case Expression::Id::I31NewId:
-          DELEGATE(I31New);
-        case Expression::Id::I31GetId:
-          DELEGATE(I31Get);
-        case Expression::Id::RefTestId:
-          DELEGATE(RefTest);
-        case Expression::Id::RefCastId:
-          DELEGATE(RefCast);
-        case Expression::Id::BrOnCastId:
-          DELEGATE(BrOnCast);
-        case Expression::Id::RttCanonId:
-          DELEGATE(RttCanon);
-        case Expression::Id::RttSubId:
-          DELEGATE(RttSub);
-        case Expression::Id::StructNewId:
-          DELEGATE(StructNew);
-        case Expression::Id::StructGetId:
-          DELEGATE(StructGet);
-        case Expression::Id::StructSetId:
-          DELEGATE(StructSet);
-        case Expression::Id::ArrayNewId:
-          DELEGATE(ArrayNew);
-        case Expression::Id::ArrayGetId:
-          DELEGATE(ArrayGet);
-        case Expression::Id::ArraySetId:
-          DELEGATE(ArraySet);
-        case Expression::Id::ArrayLenId:
-          DELEGATE(ArrayLen);
-        case Expression::Id::InvalidId:
-          WASM_UNREACHABLE("unimp");
-        case Expression::Id::NumExpressionIds:
-          WASM_UNREACHABLE("unimp");
-      }
-#undef DELEGATE
-      return;
-    }
-    if (curr->is<If>()) {
-      self->pushTask(DeadCodeElimination::doVisitIf, currp);
-      if (curr->cast<If>()->ifFalse) {
-        self->pushTask(DeadCodeElimination::scan, &curr->cast<If>()->ifFalse);
-        self->pushTask(DeadCodeElimination::doAfterIfElseTrue, currp);
-      }
-      self->pushTask(DeadCodeElimination::scan, &curr->cast<If>()->ifTrue);
-      self->pushTask(DeadCodeElimination::doAfterIfCondition, currp);
-      self->pushTask(DeadCodeElimination::scan, &curr->cast<If>()->condition);
-    } else if (curr->is<Try>()) {
-      self->pushTask(DeadCodeElimination::doVisitTry, currp);
-      self->pushTask(DeadCodeElimination::scan, &curr->cast<Try>()->catchBody);
-      self->pushTask(DeadCodeElimination::doAfterTryBody, currp);
-      self->pushTask(DeadCodeElimination::scan, &curr->cast<Try>()->body);
-      self->pushTask(DeadCodeElimination::doBeforeTryBody, currp);
-    } else {
-      super::scan(self, currp);
-    }
-  }
-
-  // other things
-
-  // we don't need to drop unreachable nodes
-  Expression* drop(Expression* toDrop) {
-    if (toDrop->type == Type::unreachable) {
-      return toDrop;
-    }
-    return Builder(*getModule()).makeDrop(toDrop);
-  }
-
-  template<typename T> Expression* handleCall(T* curr) {
-    for (Index i = 0; i < curr->operands.size(); i++) {
-      if (isUnreachable(curr->operands[i])) {
-        if (i > 0) {
-          auto* block = getModule()->allocator.alloc<Block>();
-          Index newSize = i + 1;
-          block->list.resize(newSize);
-          Index j = 0;
-          for (; j < newSize; j++) {
-            block->list[j] = drop(curr->operands[j]);
-          }
-          block->finalize(curr->type);
-          return replaceCurrent(block);
-        } else {
-          return replaceCurrent(curr->operands[i]);
+      if (removeFromHere != 0) {
+        for (Index i = removeFromHere; i < list.size(); i++) {
+          typeUpdater.noteRecursiveRemoval(list[i]);
         }
+        list.resize(removeFromHere);
+        if (list.size() == 1 && list[0]->is<Unreachable>()) {
+          replaceCurrent(list[0]);
+          return;
+        }
       }
-    }
-    return curr;
-  }
-
-  void visitCall(Call* curr) {
-    handleCall(curr);
-    if (curr->isReturn) {
-      reachable = false;
-    }
-  }
-
-  void visitCallIndirect(CallIndirect* curr) {
-    if (handleCall(curr) != curr) {
-      return;
-    }
-    if (isUnreachable(curr->target)) {
-      auto* block = getModule()->allocator.alloc<Block>();
-      for (auto* operand : curr->operands) {
-        block->list.push_back(drop(operand));
+      // Finally, if there is no need for a concrete type (which is when there
+      // is one marked, but nothing breaks to it, and also the block does not
+      // have a concrete value flowing out) then remove it, which may allow
+      // more reduction.
+      if (block->type.isConcrete() && list.back()->type == Type::unreachable &&
+          !typeUpdater.hasBreaks(block)) {
+        typeUpdater.changeType(block, Type::unreachable);
       }
-      block->list.push_back(curr->target);
-      block->finalize(curr->type);
-      replaceCurrent(block);
-    }
-    if (curr->isReturn) {
-      reachable = false;
-    }
-  }
-
-  // Append the reachable operands of the current node to a block, and replace
-  // it with the block
-  void blockifyReachableOperands(std::vector<Expression*>&& list, Type type) {
-    for (size_t i = 0; i < list.size(); ++i) {
-      auto* elem = list[i];
-      if (isUnreachable(elem)) {
-        auto* replacement = elem;
-        if (i > 0) {
-          auto* block = getModule()->allocator.alloc<Block>();
-          for (size_t j = 0; j < i; ++j) {
-            block->list.push_back(drop(list[j]));
-          }
-          block->list.push_back(list[i]);
-          block->finalize(type);
-          replacement = block;
+    } else if (auto* iff = curr->dynCast<If>()) {
+      if (iff->condition->type == Type::unreachable) {
+        typeUpdater.noteRecursiveRemoval(iff->ifTrue);
+        if (iff->ifFalse) {
+          typeUpdater.noteRecursiveRemoval(iff->ifFalse);
         }
-        replaceCurrent(replacement);
+        replaceCurrent(iff->condition);
         return;
       }
+      // If both arms are unreachable, there is no need for a concrete type,
+      // which may allow more reduction.
+      if (iff->type != Type::unreachable && iff->ifFalse &&
+          iff->ifTrue->type == Type::unreachable &&
+          iff->ifFalse->type == Type::unreachable) {
+        typeUpdater.changeType(iff, Type::unreachable);
+      }
+    } else if (auto* loop = curr->dynCast<Loop>()) {
+      // The loop body may have unreachable type if it branches back to the
+      // loop top, for example. The only case we look for here is where we've
+      // already removed the entire body as dead code.
+      if (loop->body->is<Unreachable>()) {
+        replaceCurrent(loop->body);
+      }
+    } else if (auto* tryy = curr->dynCast<Try>()) {
+      // If both try body and catch body are unreachable, there is no need for a
+      // concrete type, which may allow more reduction.
+      if (tryy->type != Type::unreachable &&
+          tryy->body->type == Type::unreachable &&
+          tryy->catchBody->type == Type::unreachable) {
+        typeUpdater.changeType(tryy, Type::unreachable);
+      }
+    } else {
+      WASM_UNREACHABLE("unimplemented DCE control flow structure");
     }
   }
-
-  void visitLocalSet(LocalSet* curr) {
-    blockifyReachableOperands({curr->value}, curr->type);
-  }
-
-  void visitGlobalSet(GlobalSet* curr) {
-    blockifyReachableOperands({curr->value}, curr->type);
-  }
-
-  void visitLoad(Load* curr) {
-    blockifyReachableOperands({curr->ptr}, curr->type);
-  }
-
-  void visitStore(Store* curr) {
-    blockifyReachableOperands({curr->ptr, curr->value}, curr->type);
-  }
-
-  void visitAtomicRMW(AtomicRMW* curr) {
-    blockifyReachableOperands({curr->ptr, curr->value}, curr->type);
-  }
-
-  void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
-    blockifyReachableOperands({curr->ptr, curr->expected, curr->replacement},
-                              curr->type);
-  }
-
-  void visitUnary(Unary* curr) {
-    blockifyReachableOperands({curr->value}, curr->type);
-  }
-
-  void visitBinary(Binary* curr) {
-    blockifyReachableOperands({curr->left, curr->right}, curr->type);
-  }
-
-  void visitSelect(Select* curr) {
-    blockifyReachableOperands({curr->ifTrue, curr->ifFalse, curr->condition},
-                              curr->type);
-  }
-
-  void visitDrop(Drop* curr) {
-    blockifyReachableOperands({curr->value}, curr->type);
-  }
-
-  void visitMemorySize(MemorySize* curr) {}
-
-  void visitMemoryGrow(MemoryGrow* curr) {
-    blockifyReachableOperands({curr->delta}, curr->type);
-  }
-
-  void visitRefIsNull(RefIsNull* curr) {
-    blockifyReachableOperands({curr->value}, curr->type);
-  }
-
-  void visitRefEq(RefEq* curr) {
-    blockifyReachableOperands({curr->left, curr->right}, curr->type);
-  }
-
-  void visitFunction(Function* curr) { assert(reachableBreaks.size() == 0); }
 };
 
 Pass* createDeadCodeEliminationPass() { return new DeadCodeElimination(); }
diff --git a/binaryen/src/passes/Directize.cpp b/binaryen/src/passes/Directize.cpp
--- a/binaryen/src/passes/Directize.cpp
+++ b/binaryen/src/passes/Directize.cpp
@@ -22,7 +22,6 @@
 
 #include <unordered_map>
 
-#include "asm_v_wasm.h"
 #include "ir/table-utils.h"
 #include "ir/utils.h"
 #include "pass.h"
@@ -42,6 +41,9 @@
   FunctionDirectizer(TableUtils::FlatTable* flatTable) : flatTable(flatTable) {}
 
   void visitCallIndirect(CallIndirect* curr) {
+    if (!flatTable) {
+      return;
+    }
     if (auto* c = curr->target->dynCast<Const>()) {
       Index index = c->value.geti32();
       // If the index is invalid, or the type is wrong, we can
@@ -69,6 +71,15 @@
     }
   }
 
+  void visitCallRef(CallRef* curr) {
+    if (auto* ref = curr->target->dynCast<RefFunc>()) {
+      // We know the target!
+      replaceCurrent(
+        Builder(*getModule())
+          .makeCall(ref->func, curr->operands, curr->type, curr->isReturn));
+    }
+  }
+
   void doWalkFunction(Function* func) {
     WalkerPass<PostWalker<FunctionDirectizer>>::doWalkFunction(func);
     if (changedTypes) {
@@ -77,7 +88,9 @@
   }
 
 private:
+  // If null, then we cannot optimize call_indirects.
   TableUtils::FlatTable* flatTable;
+
   bool changedTypes = false;
 
   void replaceWithUnreachable(CallIndirect* call) {
@@ -93,23 +106,31 @@
 
 struct Directize : public Pass {
   void run(PassRunner* runner, Module* module) override {
+    bool canOptimizeCallIndirect = true;
+    TableUtils::FlatTable flatTable(module->table);
     if (!module->table.exists) {
-      return;
-    }
-    if (module->table.imported()) {
-      return;
-    }
-    for (auto& ex : module->exports) {
-      if (ex->kind == ExternalKind::Table) {
-        return;
+      canOptimizeCallIndirect = false;
+    } else if (module->table.imported()) {
+      canOptimizeCallIndirect = false;
+    } else {
+      for (auto& ex : module->exports) {
+        if (ex->kind == ExternalKind::Table) {
+          canOptimizeCallIndirect = false;
+        }
       }
+      if (!flatTable.valid) {
+        canOptimizeCallIndirect = false;
+      }
     }
-    TableUtils::FlatTable flatTable(module->table);
-    if (!flatTable.valid) {
+    // Without typed function references, all we can do is optimize table
+    // accesses, so if we can't do that, stop.
+    if (!canOptimizeCallIndirect &&
+        !module->features.hasTypedFunctionReferences()) {
       return;
     }
     // The table exists and is constant, so this is possible.
-    FunctionDirectizer(&flatTable).run(runner, module);
+    FunctionDirectizer(canOptimizeCallIndirect ? &flatTable : nullptr)
+      .run(runner, module);
   }
 };
 
diff --git a/binaryen/src/passes/DuplicateImportElimination.cpp b/binaryen/src/passes/DuplicateImportElimination.cpp
--- a/binaryen/src/passes/DuplicateImportElimination.cpp
+++ b/binaryen/src/passes/DuplicateImportElimination.cpp
@@ -20,7 +20,6 @@
 // TODO: non-function imports too
 //
 
-#include "asm_v_wasm.h"
 #include "ir/import-utils.h"
 #include "opt-utils.h"
 #include "pass.h"
diff --git a/binaryen/src/passes/EmscriptenPIC.cpp b/binaryen/src/passes/EmscriptenPIC.cpp
deleted file mode 100644
--- a/binaryen/src/passes/EmscriptenPIC.cpp
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * 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.
- */
-
-//
-// Convert LLVM PIC ABI to emscripten ABI
-//
-// When generating -fPIC code llvm will generate imports call GOT.mem and
-// GOT.func in order to access the addresses of external global data and
-// functions.
-//
-// However emscripten uses a different ABI where function and data addresses
-// are available at runtime via special `g$foo` and `fp$bar` function calls.
-//
-// Here we internalize all such wasm globals and generte code that sets their
-// value based on the result of call `g$foo` and `fp$bar` functions at runtime.
-//
-// A function called `__assign_got_enties` is generated by this pass that
-// performs all the assignments.
-//
-
-#include "abi/js.h"
-#include "asm_v_wasm.h"
-#include "ir/import-utils.h"
-#include "ir/table-utils.h"
-#include "pass.h"
-#include "shared-constants.h"
-#include "support/debug.h"
-
-#define DEBUG_TYPE "emscripten-pic"
-
-namespace wasm {
-
-static Global* ensureGlobalImport(Module* module, Name name, Type type) {
-  // See if its already imported.
-  // FIXME: O(N)
-  ImportInfo info(*module);
-  if (auto* g = info.getImportedGlobal(ENV, name)) {
-    return g;
-  }
-  // Failing that create a new import.
-  auto import = new Global;
-  import->name = name;
-  import->module = ENV;
-  import->base = name;
-  import->type = type;
-  module->addGlobal(import);
-  return import;
-}
-
-static Function*
-ensureFunctionImport(Module* module, Name name, Signature sig) {
-  // See if its already imported.
-  // FIXME: O(N)
-  ImportInfo info(*module);
-  if (auto* f = info.getImportedFunction(ENV, name)) {
-    return f;
-  }
-  // Failing that create a new import.
-  auto import = new Function;
-  import->name = name;
-  import->module = ENV;
-  import->base = name;
-  import->sig = sig;
-  module->addFunction(import);
-  return import;
-}
-
-struct EmscriptenPIC : public WalkerPass<PostWalker<EmscriptenPIC>> {
-
-  EmscriptenPIC(bool sideModule) : sideModule(sideModule) {}
-
-  void visitGlobal(Global* curr) {
-    if (!curr->imported()) {
-      return;
-    }
-    if (curr->module == "GOT.func") {
-      gotFuncEntries.push_back(curr);
-    } else if (curr->module == "GOT.mem") {
-      gotMemEntries.push_back(curr);
-    } else {
-      return;
-    }
-    // Make this an internal, non-imported, global.
-    curr->module.clear();
-    curr->init = Builder(*getModule()).makeConst(int32_t(0));
-  }
-
-  void visitModule(Module* module) {
-    BYN_TRACE("generateAssignGOTEntriesFunction\n");
-    if (!gotFuncEntries.size() && !gotMemEntries.size()) {
-      return;
-    }
-
-    Builder builder(*getModule());
-    Function* assignFunc = builder.makeFunction(
-      ASSIGN_GOT_ENTRIES, std::vector<NameType>{}, Type::none, {});
-    Block* block = builder.makeBlock();
-    assignFunc->body = block;
-
-    bool hasSingleMemorySegment =
-      module->memory.exists && module->memory.segments.size() == 1;
-
-    for (Global* g : gotMemEntries) {
-      // If this global is defined in this module, we export its address
-      // relative to the relocatable memory. If we are in a main module, we can
-      // just use that location (since if other modules have this symbol too, we
-      // will "win" as we are loaded first). Otherwise, import a g$ getter. Note
-      // that this depends on memory having a single segment, so we know the
-      // offset, and that the export is a global.
-      auto base = g->base;
-      if (hasSingleMemorySegment && !sideModule) {
-        if (auto* ex = module->getExportOrNull(base)) {
-          if (ex->kind == ExternalKind::Global) {
-            // The base relative to which we are computed is the offset of the
-            // singleton segment.
-            auto* relativeBase = ExpressionManipulator::copy(
-              module->memory.segments[0].offset, *module);
-
-            auto* offset = builder.makeGlobalGet(
-              ex->value, module->getGlobal(ex->value)->type);
-            auto* add = builder.makeBinary(AddInt32, relativeBase, offset);
-            GlobalSet* globalSet = builder.makeGlobalSet(g->name, add);
-            block->list.push_back(globalSet);
-            continue;
-          }
-        }
-      }
-      Name getter(std::string("g$") + base.c_str());
-      ensureFunctionImport(module, getter, Signature(Type::none, Type::i32));
-      Expression* call = builder.makeCall(getter, {}, Type::i32);
-      GlobalSet* globalSet = builder.makeGlobalSet(g->name, call);
-      block->list.push_back(globalSet);
-    }
-
-    ImportInfo importInfo(*module);
-
-    // We may have to add things to the table.
-    Global* tableBase = nullptr;
-
-    for (Global* g : gotFuncEntries) {
-      // The function has to exist either as export or an import.
-      // Note that we don't search for the function by name since its internal
-      // name may be different.
-      auto* ex = module->getExportOrNull(g->base);
-      // If this is exported then it must be one of the functions implemented
-      // here, and if this is a main module, then we can simply place the
-      // function in the table: the loader will see it there and resolve all
-      // other uses to this one.
-      if (ex && !sideModule) {
-        assert(ex->kind == ExternalKind::Function);
-        auto* f = module->getFunction(ex->value);
-        if (f->imported()) {
-          Fatal() << "GOT.func entry is both imported and exported: "
-                  << g->base;
-        }
-        // The base relative to which we are computed is the offset of the
-        // singleton segment, which we must ensure exists
-        if (!tableBase) {
-          tableBase = ensureGlobalImport(module, TABLE_BASE, Type::i32);
-        }
-        if (!module->table.exists) {
-          module->table.exists = true;
-        }
-        if (module->table.segments.empty()) {
-          module->table.segments.resize(1);
-          module->table.segments[0].offset =
-            builder.makeGlobalGet(tableBase->name, Type::i32);
-        }
-        auto tableIndex =
-          TableUtils::getOrAppend(module->table, f->name, *module);
-        auto* c = LiteralUtils::makeFromInt32(tableIndex, Type::i32, *module);
-        auto* getBase = builder.makeGlobalGet(tableBase->name, Type::i32);
-        auto* add = builder.makeBinary(AddInt32, getBase, c);
-        auto* globalSet = builder.makeGlobalSet(g->name, add);
-        block->list.push_back(globalSet);
-        continue;
-      }
-      // This is imported or in a side module. Create an fp$ import to get the
-      // function table index from the dynamic loader.
-      auto* f = importInfo.getImportedFunction(ENV, g->base);
-      if (!f) {
-        if (!ex) {
-          Fatal() << "GOT.func entry with no import/export: " << g->base;
-        }
-        f = module->getFunction(ex->value);
-      }
-      Name getter(
-        (std::string("fp$") + g->base.c_str() + std::string("$") + getSig(f))
-          .c_str());
-      ensureFunctionImport(module, getter, Signature(Type::none, Type::i32));
-      auto* call = builder.makeCall(getter, {}, Type::i32);
-      auto* globalSet = builder.makeGlobalSet(g->name, call);
-      block->list.push_back(globalSet);
-    }
-
-    module->addFunction(assignFunc);
-  }
-
-  std::vector<Global*> gotFuncEntries;
-  std::vector<Global*> gotMemEntries;
-  bool sideModule;
-};
-
-Pass* createEmscriptenPICPass() { return new EmscriptenPIC(true); }
-
-Pass* createEmscriptenPICMainModulePass() { return new EmscriptenPIC(false); }
-
-} // namespace wasm
diff --git a/binaryen/src/passes/Flatten.cpp b/binaryen/src/passes/Flatten.cpp
--- a/binaryen/src/passes/Flatten.cpp
+++ b/binaryen/src/passes/Flatten.cpp
@@ -17,6 +17,8 @@
 //
 // Flattens code into "Flat IR" form. See ir/flat.h.
 //
+// TODO: handle non-nullability
+//
 
 #include <ir/branch-utils.h>
 #include <ir/effects.h>
diff --git a/binaryen/src/passes/FuncCastEmulation.cpp b/binaryen/src/passes/FuncCastEmulation.cpp
--- a/binaryen/src/passes/FuncCastEmulation.cpp
+++ b/binaryen/src/passes/FuncCastEmulation.cpp
@@ -28,7 +28,8 @@
 // params must be identical, i.e., the "ABI" must match.
 //
 
-#include <asm_v_wasm.h>
+#include <string>
+
 #include <ir/literal-utils.h>
 #include <pass.h>
 #include <wasm-builder.h>
@@ -36,11 +37,6 @@
 
 namespace wasm {
 
-// This should be enough for everybody. (As described above, we need this
-// to match when dynamically linking, and also dynamic linking is why we
-// can't just detect this automatically in the module we see.)
-static const int NUM_PARAMS = 16;
-
 // Converts a value to the ABI type of i64.
 static Expression* toABI(Expression* value, Module* module) {
   Builder builder(*module);
@@ -134,20 +130,23 @@
   : public WalkerPass<PostWalker<ParallelFuncCastEmulation>> {
   bool isFunctionParallel() override { return true; }
 
-  Pass* create() override { return new ParallelFuncCastEmulation(ABIType); }
+  Pass* create() override {
+    return new ParallelFuncCastEmulation(ABIType, numParams);
+  }
 
-  ParallelFuncCastEmulation(Signature ABIType) : ABIType(ABIType) {}
+  ParallelFuncCastEmulation(Signature ABIType, Index numParams)
+    : ABIType(ABIType), numParams(numParams) {}
 
   void visitCallIndirect(CallIndirect* curr) {
-    if (curr->operands.size() > NUM_PARAMS) {
-      Fatal() << "FuncCastEmulation::NUM_PARAMS needs to be at least "
+    if (curr->operands.size() > numParams) {
+      Fatal() << "max-func-params needs to be at least "
               << curr->operands.size();
     }
     for (Expression*& operand : curr->operands) {
       operand = toABI(operand, getModule());
     }
     // Add extra operands as needed.
-    while (curr->operands.size() < NUM_PARAMS) {
+    while (curr->operands.size() < numParams) {
       curr->operands.push_back(LiteralUtils::makeZero(Type::i64, *getModule()));
     }
     // Set the new types
@@ -162,20 +161,22 @@
 private:
   // The signature of a call with the right params and return
   Signature ABIType;
+  Index numParams;
 };
 
 struct FuncCastEmulation : public Pass {
   void run(PassRunner* runner, Module* module) override {
+    Index numParams =
+      std::stoul(runner->options.getArgumentOrDefault("max-func-params", "16"));
     // we just need the one ABI function type for all indirect calls
-    Signature ABIType(Type(std::vector<Type>(NUM_PARAMS, Type::i64)),
-                      Type::i64);
+    Signature ABIType(Type(std::vector<Type>(numParams, Type::i64)), Type::i64);
     // Add a thunk for each function in the table, and do the call through it.
     std::unordered_map<Name, Name> funcThunks;
     for (auto& segment : module->table.segments) {
       for (auto& name : segment.data) {
         auto iter = funcThunks.find(name);
         if (iter == funcThunks.end()) {
-          auto thunk = makeThunk(name, module);
+          auto thunk = makeThunk(name, module, numParams);
           funcThunks[name] = thunk;
           name = thunk;
         } else {
@@ -184,12 +185,12 @@
       }
     }
     // update call_indirects
-    ParallelFuncCastEmulation(ABIType).run(runner, module);
+    ParallelFuncCastEmulation(ABIType, numParams).run(runner, module);
   }
 
 private:
   // Creates a thunk for a function, casting args and return value as needed.
-  Name makeThunk(Name name, Module* module) {
+  Name makeThunk(Name name, Module* module, Index numParams) {
     Name thunk = std::string("byn$fpcast-emu$") + name.str;
     if (module->getFunctionOrNull(thunk)) {
       Fatal() << "FuncCastEmulation::makeThunk seems a thunk name already in "
@@ -207,15 +208,15 @@
     }
     auto* call = builder.makeCall(name, callOperands, type);
     std::vector<Type> thunkParams;
-    for (Index i = 0; i < NUM_PARAMS; i++) {
+    for (Index i = 0; i < numParams; i++) {
       thunkParams.push_back(Type::i64);
     }
-    auto* thunkFunc =
+    auto thunkFunc =
       builder.makeFunction(thunk,
                            Signature(Type(thunkParams), Type::i64),
                            {}, // no vars
                            toABI(call, module));
-    module->addFunction(thunkFunc);
+    module->addFunction(std::move(thunkFunc));
     return thunk;
   }
 };
diff --git a/binaryen/src/passes/GenerateDynCalls.cpp b/binaryen/src/passes/GenerateDynCalls.cpp
--- a/binaryen/src/passes/GenerateDynCalls.cpp
+++ b/binaryen/src/passes/GenerateDynCalls.cpp
@@ -120,7 +120,7 @@
   for (const auto& param : sig.params) {
     params.emplace_back(std::to_string(p++), param);
   }
-  Function* f = builder.makeFunction(name, std::move(params), sig.results, {});
+  auto f = builder.makeFunction(name, std::move(params), sig.results, {});
   Expression* fptr = builder.makeLocalGet(0, Type::i32);
   std::vector<Expression*> args;
   Index i = 0;
@@ -130,8 +130,8 @@
   Expression* call = builder.makeCallIndirect(fptr, args, sig);
   f->body = call;
 
-  wasm->addFunction(f);
-  exportFunction(*wasm, f->name, true);
+  wasm->addFunction(std::move(f));
+  exportFunction(*wasm, name, true);
 }
 
 Pass* createGenerateDynCallsPass() { return new GenerateDynCalls(false); }
diff --git a/binaryen/src/passes/I64ToI32Lowering.cpp b/binaryen/src/passes/I64ToI32Lowering.cpp
--- a/binaryen/src/passes/I64ToI32Lowering.cpp
+++ b/binaryen/src/passes/I64ToI32Lowering.cpp
@@ -22,7 +22,6 @@
 //
 
 #include "abi/js.h"
-#include "asmjs/shared-constants.h"
 #include "emscripten-optimizer/istring.h"
 #include "ir/flat.h"
 #include "ir/iteration.h"
@@ -114,11 +113,10 @@
       }
       originallyI64Globals.insert(curr->name);
       curr->type = Type::i32;
-      auto* high = builder->makeGlobal(makeHighName(curr->name),
-                                       Type::i32,
-                                       builder->makeConst(int32_t(0)),
-                                       Builder::Mutable);
-      module->addGlobal(high);
+      auto high = builder->makeGlobal(makeHighName(curr->name),
+                                      Type::i32,
+                                      builder->makeConst(int32_t(0)),
+                                      Builder::Mutable);
       if (curr->imported()) {
         Fatal() << "TODO: imported i64 globals";
       } else {
@@ -135,6 +133,7 @@
         }
         curr->init->type = Type::i32;
       }
+      module->addGlobal(std::move(high));
     }
 
     // For functions that return 64-bit values, we use this global variable
@@ -219,6 +218,9 @@
   // returns nullptr;
   template<typename T>
   T* visitGenericCall(T* curr, BuilderFunc<T> callBuilder) {
+    if (handleUnreachable(curr)) {
+      return nullptr;
+    }
     bool fixed = false;
     std::vector<Expression*> args;
     for (auto* e : curr->operands) {
diff --git a/binaryen/src/passes/Inlining.cpp b/binaryen/src/passes/Inlining.cpp
--- a/binaryen/src/passes/Inlining.cpp
+++ b/binaryen/src/passes/Inlining.cpp
@@ -17,8 +17,6 @@
 //
 // Inlining.
 //
-// This uses some simple heuristics to decide when to inline.
-//
 // Two versions are provided: inlining and inlining-optimizing. You
 // probably want the optimizing version, which will optimize locations
 // we inlined into, as inlining by itself creates a block to house the
@@ -62,25 +60,21 @@
 
   // See pass.h for how defaults for these options were chosen.
   bool worthInlining(PassOptions& options) {
-    // if it's big, it's just not worth doing (TODO: investigate more)
-    if (size > options.inlining.flexibleInlineMaxSize) {
-      return false;
-    }
-    // if it's so small we have a guarantee that after we optimize the
-    // size will not increase, inline it
+    // If it's small enough that we always want to inline such things, do so.
     if (size <= options.inlining.alwaysInlineMaxSize) {
       return true;
     }
-    // if it has one use, then inlining it would likely reduce code size
-    // since we are just moving code around, + optimizing, so worth it
-    // if small enough that we are pretty sure its ok
-    // FIXME: move this check to be first in this function, since we should
-    // return true if oneCallerInlineMaxSize is bigger than
-    // flexibleInlineMaxSize (which it typically should be).
+    // If it has one use, then inlining it would likely reduce code size, at
+    // least for reasonable function sizes.
     if (refs == 1 && !usedGlobally &&
         size <= options.inlining.oneCallerInlineMaxSize) {
       return true;
     }
+    // If it's so big that we have no flexible options that could allow it,
+    // do not inline.
+    if (size > options.inlining.flexibleInlineMaxSize) {
+      return false;
+    }
     // More than one use, so we can't eliminate it after inlining,
     // so only worth it if we really care about speed and don't care
     // about size. First, check if it has calls. In that case it is not
@@ -217,6 +211,12 @@
       handleReturnCall(curr, curr->sig.results);
     }
   }
+  void visitCallRef(CallRef* curr) {
+    if (curr->isReturn) {
+      handleReturnCall(curr,
+                       curr->target->type.getHeapType().getSignature().results);
+    }
+  }
   void visitLocalGet(LocalGet* curr) {
     curr->index = localMapping[curr->index];
   }
@@ -326,7 +326,6 @@
     PassRunner runner(module);
     FunctionInfoScanner(&infos).run(&runner, module);
     // fill in global uses
-    // anything exported or used in a table should not be inlined
     for (auto& ex : module->exports) {
       if (ex->kind == ExternalKind::Function) {
         infos[ex->value].usedGlobally = true;
@@ -336,6 +335,16 @@
       for (auto name : segment.data) {
         infos[name].usedGlobally = true;
       }
+    }
+    for (auto& global : module->globals) {
+      if (!global->imported()) {
+        for (auto* ref : FindAll<RefFunc>(global->init).list) {
+          infos[ref->func].usedGlobally = true;
+        }
+      }
+    }
+    if (module->start.is()) {
+      infos[module->start].usedGlobally = true;
     }
   }
 
diff --git a/binaryen/src/passes/InstrumentLocals.cpp b/binaryen/src/passes/InstrumentLocals.cpp
--- a/binaryen/src/passes/InstrumentLocals.cpp
+++ b/binaryen/src/passes/InstrumentLocals.cpp
@@ -43,7 +43,6 @@
 //    )
 //   )
 
-#include "asm_v_wasm.h"
 #include "asmjs/shared-constants.h"
 #include "shared-constants.h"
 #include <pass.h>
@@ -135,8 +134,13 @@
 
     Builder builder(*getModule());
     Name import;
+    auto type = curr->value->type;
+    if (type.isFunction() && type != Type::funcref) {
+      // FIXME: support typed function references
+      return;
+    }
     TODO_SINGLE_COMPOUND(curr->value->type);
-    switch (curr->value->type.getBasic()) {
+    switch (type.getBasic()) {
       case Type::i32:
         import = set_i32;
         break;
@@ -171,7 +175,7 @@
         break;
       case Type::unreachable:
         return; // nothing to do here
-      case Type::none:
+      default:
         WASM_UNREACHABLE("unexpected type");
     }
     curr->value = builder.makeCall(import,
diff --git a/binaryen/src/passes/InstrumentMemory.cpp b/binaryen/src/passes/InstrumentMemory.cpp
--- a/binaryen/src/passes/InstrumentMemory.cpp
+++ b/binaryen/src/passes/InstrumentMemory.cpp
@@ -52,7 +52,6 @@
 //    )
 //   )
 
-#include "asm_v_wasm.h"
 #include "asmjs/shared-constants.h"
 #include "shared-constants.h"
 #include <pass.h>
diff --git a/binaryen/src/passes/LegalizeJSInterface.cpp b/binaryen/src/passes/LegalizeJSInterface.cpp
--- a/binaryen/src/passes/LegalizeJSInterface.cpp
+++ b/binaryen/src/passes/LegalizeJSInterface.cpp
@@ -30,7 +30,6 @@
 // table even to a signature that is not legal.
 //
 
-#include "asm_v_wasm.h"
 #include "asmjs/shared-constants.h"
 #include "ir/import-utils.h"
 #include "ir/literal-utils.h"
@@ -54,7 +53,7 @@
          .getArgumentOrDefault("legalize-js-interface-export-originals", "")
          .empty();
     // for each illegal export, we must export a legalized stub instead
-    std::vector<Export*> newExports;
+    std::vector<std::unique_ptr<Export>> newExports;
     for (auto& ex : module->exports) {
       if (ex->kind == ExternalKind::Function) {
         // if it's an import, ignore it
@@ -82,8 +81,8 @@
         }
       }
     }
-    for (auto* ex : newExports) {
-      module->addExport(ex);
+    for (auto& ex : newExports) {
+      module->addExport(std::move(ex));
     }
     // Avoid iterator invalidation later.
     std::vector<Function*> originalFunctions;
diff --git a/binaryen/src/passes/LogExecution.cpp b/binaryen/src/passes/LogExecution.cpp
--- a/binaryen/src/passes/LogExecution.cpp
+++ b/binaryen/src/passes/LogExecution.cpp
@@ -28,7 +28,6 @@
 // value.
 //
 
-#include "asm_v_wasm.h"
 #include "asmjs/shared-constants.h"
 #include "shared-constants.h"
 #include <pass.h>
diff --git a/binaryen/src/passes/LoopInvariantCodeMotion.cpp b/binaryen/src/passes/LoopInvariantCodeMotion.cpp
--- a/binaryen/src/passes/LoopInvariantCodeMotion.cpp
+++ b/binaryen/src/passes/LoopInvariantCodeMotion.cpp
@@ -114,17 +114,20 @@
       }
       if (interestingToMove(curr)) {
         // Let's see if we can move this out.
-        // Global side effects would prevent this - we might end up
+        // Global state changes would prevent this - we might end up
         // executing them just once.
         // And we must also move across anything not moved out already,
         // so check for issues there too.
         // The rest of the loop's effects matter too, we must also
         // take into account global state like interacting loads and
         // stores.
-        bool unsafeToMove = effects.hasGlobalSideEffects() ||
-                            effectsSoFar.invalidates(effects) ||
-                            (effects.noticesGlobalSideEffects() &&
-                             loopEffects.hasGlobalSideEffects());
+        bool unsafeToMove =
+          effects.writesGlobalState() || effectsSoFar.invalidates(effects) ||
+          (effects.readsGlobalState() && loopEffects.writesGlobalState());
+        // TODO: look into optimizing this with exceptions. for now, disallow
+        if (effects.throws || loopEffects.throws) {
+          unsafeToMove = true;
+        }
         if (!unsafeToMove) {
           // So far so good. Check if our local dependencies are all
           // outside of the loop, in which case everything is good -
diff --git a/binaryen/src/passes/Memory64Lowering.cpp b/binaryen/src/passes/Memory64Lowering.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/passes/Memory64Lowering.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 extendAddress64(Expression*& ptr) {
+    if (ptr->type == Type::unreachable) {
+      return;
+    }
+    auto& module = *getModule();
+    assert(module.memory.is64());
+    assert(ptr->type == Type::i64);
+    ptr->type = Type::i32;
+    Builder builder(module);
+    ptr = builder.makeUnary(UnaryOp::ExtendUInt32, 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);
+    extendAddress64(size);
+    curr->ptrType = Type::i32;
+    replaceCurrent(size);
+  }
+
+  void visitMemoryGrow(MemoryGrow* curr) {
+    wrapAddress64(curr->delta);
+    auto size = static_cast<Expression*>(curr);
+    extendAddress64(size);
+    curr->ptrType = Type::i32;
+    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/binaryen/src/passes/MemoryPacking.cpp b/binaryen/src/passes/MemoryPacking.cpp
--- a/binaryen/src/passes/MemoryPacking.cpp
+++ b/binaryen/src/passes/MemoryPacking.cpp
@@ -30,14 +30,18 @@
 
 #include "ir/manipulation.h"
 #include "ir/module-utils.h"
+#include "ir/names.h"
 #include "ir/utils.h"
 #include "pass.h"
+#include "support/space.h"
 #include "wasm-binary.h"
 #include "wasm-builder.h"
 #include "wasm.h"
 
 namespace wasm {
 
+namespace {
+
 // A subsection of an orginal memory segment. If `isZero` is true, memory.fill
 // will be used instead of memory.init for this range.
 struct Range {
@@ -74,8 +78,6 @@
 // data.drop: 2 byte opcode + ~1 byte index immediate
 const size_t DATA_DROP_SIZE = 3;
 
-namespace {
-
 Expression*
 makeGtShiftedMemorySize(Builder& builder, Module& module, MemoryInit* curr) {
   return builder.makeBinary(
@@ -89,14 +91,13 @@
 } // anonymous namespace
 
 struct MemoryPacking : public Pass {
-  size_t dropStateGlobalCount = 0;
-
   // FIXME: Chrome has a bug decoding section indices that prevents it from
   // using more than 63. Just use WebLimitations::MaxDataSegments once this is
   // fixed. See https://bugs.chromium.org/p/v8/issues/detail?id=10151.
   uint32_t maxSegments;
 
   void run(PassRunner* runner, Module* module) override;
+  bool canOptimize(const Memory& memory, const PassOptions& passOptions);
   void optimizeBulkMemoryOps(PassRunner* runner, Module* module);
   void getSegmentReferrers(Module* module, std::vector<Referrers>& referrers);
   void dropUnusedSegments(std::vector<Memory::Segment>& segments,
@@ -121,13 +122,14 @@
 };
 
 void MemoryPacking::run(PassRunner* runner, Module* module) {
-  if (!module->memory.exists) {
+  if (!canOptimize(module->memory, runner->options)) {
     return;
   }
 
   maxSegments = module->features.hasBulkMemory()
                   ? 63
                   : uint32_t(WebLimitations::MaxDataSegments);
+
   auto& segments = module->memory.segments;
 
   // For each segment, a list of bulk memory instructions that refer to it
@@ -154,6 +156,7 @@
     auto& currReferrers = referrers[origIndex];
 
     std::vector<Range> ranges;
+
     if (canSplit(segment, currReferrers)) {
       calculateRanges(segment, currReferrers, ranges);
     } else {
@@ -176,8 +179,88 @@
   }
 }
 
+bool MemoryPacking::canOptimize(const Memory& memory,
+                                const PassOptions& passOptions) {
+  if (!memory.exists) {
+    return false;
+  }
+
+  // We must optimize under the assumption that memory has been initialized to
+  // zero. That is the case for a memory declared in the module, but for a
+  // memory that is imported, we must be told that it is zero-initialized.
+  if (memory.imported() && !passOptions.zeroFilledMemory) {
+    return false;
+  }
+
+  auto& segments = memory.segments;
+
+  // One segment is always ok to optimize, as it does not have the potential
+  // problems handled below.
+  if (segments.size() <= 1) {
+    return true;
+  }
+  // Check if it is ok for us to optimize.
+  Address maxAddress = 0;
+  for (auto& segment : segments) {
+    if (!segment.isPassive) {
+      auto* c = segment.offset->dynCast<Const>();
+      // If an active segment has a non-constant offset, then what gets written
+      // cannot be known until runtime. That is, the active segments are written
+      // out at startup, in order, and one may trample the data of another, like
+      //
+      //  (data (i32.const 100) "a")
+      //  (data (i32.const 100) "\00")
+      //
+      // It is *not* ok to optimize out the zero in the last segment, as it is
+      // actually needed, it will zero out the "a" that was written earlier. And
+      // if a segment has an imported offset,
+      //
+      //  (data (i32.const 100) "a")
+      //  (data (global.get $x) "\00")
+      //
+      // then we can't tell if that last segment will end up overwriting or not.
+      // The only case we can easily handle is if there is just a single
+      // segment, which we handled earlier. (Note that that includes the main
+      // case of having a non-constant offset, dynamic linking, in which we have
+      // a single segment.)
+      if (!c) {
+        return false;
+      }
+      // Note the maximum address so far.
+      maxAddress = std::max(
+        maxAddress, Address(c->value.getInteger() + segment.data.size()));
+    }
+  }
+  // All active segments have constant offsets, known at this time, so we may be
+  // able to optimize, but must still check for the trampling problem mentioned
+  // earlier.
+  // TODO: optimize in the trampling case
+  DisjointSpans space;
+  for (auto& segment : segments) {
+    if (!segment.isPassive) {
+      auto* c = segment.offset->cast<Const>();
+      Address start = c->value.getInteger();
+      DisjointSpans::Span span{start, start + segment.data.size()};
+      if (space.addAndCheckOverlap(span)) {
+        std::cerr << "warning: active memory segments have overlap, which "
+                  << "prevents some optimizations.\n";
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
 bool MemoryPacking::canSplit(const Memory::Segment& segment,
                              const Referrers& referrers) {
+  // Don't mess with segments related to llvm coverage tools such as
+  // __llvm_covfun. There segments are expected/parsed by external downstream
+  // tools (llvm-cov) so they need to be left intact.
+  // See https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
+  if (segment.name.is() && segment.name.startsWith("__llvm")) {
+    return false;
+  }
+
   if (segment.isPassive) {
     for (auto* referrer : referrers) {
       if (auto* init = referrer->dynCast<MemoryInit>()) {
@@ -188,10 +271,10 @@
       }
     }
     return true;
-  } else {
-    // Active segments can only be split if they have constant offsets
-    return segment.offset->is<Const>();
   }
+
+  // Active segments can only be split if they have constant offsets
+  return segment.offset->is<Const>();
 }
 
 void MemoryPacking::calculateRanges(const Memory::Segment& segment,
@@ -431,6 +514,7 @@
                                         std::vector<Range>& ranges,
                                         std::vector<Memory::Segment>& packed,
                                         size_t segmentsRemaining) {
+  size_t segmentCount = 0;
   for (size_t i = 0; i < ranges.size(); ++i) {
     Range& range = ranges[i];
     if (range.isZero) {
@@ -454,7 +538,22 @@
       range.end = lastNonzero->end;
       ranges.erase(ranges.begin() + i + 1, lastNonzero + 1);
     }
-    packed.emplace_back(segment.isPassive,
+    Name name;
+    if (segment.name.is()) {
+      // Name the first range after the original segment and all following
+      // ranges get numbered accordingly.  This means that for segments that
+      // canot be split (segments that contains a single range) the input and
+      // output segment have the same name.
+      if (!segmentCount) {
+        name = segment.name;
+      } else {
+        name = std::string(segment.name.c_str()) + "." +
+               std::to_string(segmentCount);
+      }
+      segmentCount++;
+    }
+    packed.emplace_back(name,
+                        segment.isPassive,
                         offset,
                         &segment.data[range.start],
                         range.end - range.start);
@@ -494,8 +593,8 @@
     if (dropStateGlobal != Name()) {
       return dropStateGlobal;
     }
-    dropStateGlobal = Name(std::string("__mem_segment_drop_state_") +
-                           std::to_string(dropStateGlobalCount++));
+    dropStateGlobal =
+      Names::getValidGlobalName(*module, "__mem_segment_drop_state");
     module->addGlobal(builder.makeGlobal(dropStateGlobal,
                                          Type::i32,
                                          builder.makeConst(int32_t(0)),
@@ -514,10 +613,16 @@
     size_t start = init->offset->cast<Const>()->value.geti32();
     size_t end = start + init->size->cast<Const>()->value.geti32();
 
+    // Segment index used in emitted memory.init instructions
+    size_t initIndex = segmentIndex;
+
     // Index of the range from which this memory.init starts reading
     size_t firstRangeIdx = 0;
     while (firstRangeIdx < ranges.size() &&
            ranges[firstRangeIdx].end <= start) {
+      if (!ranges[firstRangeIdx].isZero) {
+        ++initIndex;
+      }
       ++firstRangeIdx;
     }
 
@@ -568,7 +673,6 @@
 
     size_t bytesWritten = 0;
 
-    size_t initIndex = segmentIndex;
     for (size_t i = firstRangeIdx; i < ranges.size() && ranges[i].start < end;
          ++i) {
       auto& range = ranges[i];
diff --git a/binaryen/src/passes/MergeBlocks.cpp b/binaryen/src/passes/MergeBlocks.cpp
--- a/binaryen/src/passes/MergeBlocks.cpp
+++ b/binaryen/src/passes/MergeBlocks.cpp
@@ -564,7 +564,7 @@
 
   void visitCall(Call* curr) { handleCall(curr); }
 
-  void visitCallIndirect(CallIndirect* curr) {
+  template<typename T> void handleNonDirectCall(T* curr) {
     FeatureSet features = getModule()->features;
     Block* outer = nullptr;
     for (Index i = 0; i < curr->operands.size(); i++) {
@@ -580,6 +580,10 @@
     }
     optimize(curr, curr->target, outer);
   }
+
+  void visitCallIndirect(CallIndirect* curr) { handleNonDirectCall(curr); }
+
+  void visitCallRef(CallRef* curr) { handleNonDirectCall(curr); }
 
   void visitThrow(Throw* curr) {
     Block* outer = nullptr;
diff --git a/binaryen/src/passes/OptimizeInstructions.cpp b/binaryen/src/passes/OptimizeInstructions.cpp
--- a/binaryen/src/passes/OptimizeInstructions.cpp
+++ b/binaryen/src/passes/OptimizeInstructions.cpp
@@ -19,1938 +19,2439 @@
 //
 
 #include <algorithm>
-#include <type_traits>
-
-#include <ir/abstract.h>
-#include <ir/bits.h>
-#include <ir/cost.h>
-#include <ir/effects.h>
-#include <ir/literal-utils.h>
-#include <ir/load-utils.h>
-#include <ir/manipulation.h>
-#include <ir/match.h>
-#include <ir/properties.h>
-#include <ir/utils.h>
-#include <pass.h>
-#include <support/threads.h>
-#include <wasm-s-parser.h>
-#include <wasm.h>
-
-// TODO: Use the new sign-extension opcodes where appropriate. This needs to be
-// conditionalized on the availability of atomics.
-
-namespace wasm {
-
-Name I32_EXPR = "i32.expr";
-Name I64_EXPR = "i64.expr";
-Name F32_EXPR = "f32.expr";
-Name F64_EXPR = "f64.expr";
-Name ANY_EXPR = "any.expr";
-
-// Useful information about locals
-struct LocalInfo {
-  static const Index kUnknown = Index(-1);
-
-  Index maxBits;
-  Index signExtedBits;
-};
-
-struct LocalScanner : PostWalker<LocalScanner> {
-  std::vector<LocalInfo>& localInfo;
-  const PassOptions& passOptions;
-
-  LocalScanner(std::vector<LocalInfo>& localInfo,
-               const PassOptions& passOptions)
-    : localInfo(localInfo), passOptions(passOptions) {}
-
-  void doWalkFunction(Function* func) {
-    // prepare
-    localInfo.resize(func->getNumLocals());
-    for (Index i = 0; i < func->getNumLocals(); i++) {
-      auto& info = localInfo[i];
-      if (func->isParam(i)) {
-        info.maxBits = getBitsForType(func->getLocalType(i)); // worst-case
-        info.signExtedBits = LocalInfo::kUnknown; // we will never know anything
-      } else {
-        info.maxBits = info.signExtedBits = 0; // we are open to learning
-      }
-    }
-    // walk
-    PostWalker<LocalScanner>::doWalkFunction(func);
-    // finalize
-    for (Index i = 0; i < func->getNumLocals(); i++) {
-      auto& info = localInfo[i];
-      if (info.signExtedBits == LocalInfo::kUnknown) {
-        info.signExtedBits = 0;
-      }
-    }
-  }
-
-  void visitLocalSet(LocalSet* curr) {
-    auto* func = getFunction();
-    if (func->isParam(curr->index)) {
-      return;
-    }
-    auto type = getFunction()->getLocalType(curr->index);
-    if (type != Type::i32 && type != Type::i64) {
-      return;
-    }
-    // an integer var, worth processing
-    auto* value = Properties::getFallthrough(
-      curr->value, passOptions, getModule()->features);
-    auto& info = localInfo[curr->index];
-    info.maxBits = std::max(info.maxBits, Bits::getMaxBits(value, this));
-    auto signExtBits = LocalInfo::kUnknown;
-    if (Properties::getSignExtValue(value)) {
-      signExtBits = Properties::getSignExtBits(value);
-    } else if (auto* load = value->dynCast<Load>()) {
-      if (LoadUtils::isSignRelevant(load) && load->signed_) {
-        signExtBits = load->bytes * 8;
-      }
-    }
-    if (info.signExtedBits == 0) {
-      info.signExtedBits = signExtBits; // first info we see
-    } else if (info.signExtedBits != signExtBits) {
-      // contradictory information, give up
-      info.signExtedBits = LocalInfo::kUnknown;
-    }
-  }
-
-  // define this for the templated getMaxBits method. we know nothing here yet
-  // about locals, so return the maxes
-  Index getMaxBitsForLocal(LocalGet* get) { return getBitsForType(get->type); }
-
-  Index getBitsForType(Type type) {
-    TODO_SINGLE_COMPOUND(type);
-    switch (type.getBasic()) {
-      case Type::i32:
-        return 32;
-      case Type::i64:
-        return 64;
-      default:
-        return -1;
-    }
-  }
-};
-
-// Create a custom matcher for checking side effects
-template<class Opt> struct PureMatcherKind {};
-template<class Opt>
-struct Match::Internal::KindTypeRegistry<PureMatcherKind<Opt>> {
-  using matched_t = Expression*;
-  using data_t = Opt*;
-};
-template<class Opt> struct Match::Internal::MatchSelf<PureMatcherKind<Opt>> {
-  bool operator()(Expression* curr, Opt* opt) {
-    return !opt->effects(curr).hasSideEffects();
-  }
-};
-
-// Main pass class
-struct OptimizeInstructions
-  : public WalkerPass<
-      PostWalker<OptimizeInstructions,
-                 UnifiedExpressionVisitor<OptimizeInstructions>>> {
-  bool isFunctionParallel() override { return true; }
-
-  Pass* create() override { return new OptimizeInstructions; }
-
-  bool fastMath;
-
-  void doWalkFunction(Function* func) {
-    fastMath = getPassOptions().fastMath;
-    // first, scan locals
-    {
-      LocalScanner scanner(localInfo, getPassOptions());
-      scanner.setModule(getModule());
-      scanner.walkFunction(func);
-    }
-    // main walk
-    super::doWalkFunction(func);
-  }
-
-  void visitExpression(Expression* curr) {
-    // we may be able to apply multiple patterns, one may open opportunities
-    // that look deeper NB: patterns must not have cycles
-    while (1) {
-      auto* handOptimized = handOptimize(curr);
-      if (handOptimized) {
-        curr = handOptimized;
-        replaceCurrent(curr);
-        continue;
-      }
-      break;
-    }
-  }
-
-  EffectAnalyzer effects(Expression* expr) {
-    return EffectAnalyzer(getPassOptions(), getModule()->features, expr);
-  }
-
-  decltype(auto) pure(Expression** binder) {
-    using namespace Match::Internal;
-    return Matcher<PureMatcherKind<OptimizeInstructions>>(binder, this);
-  }
-
-  bool canReorder(Expression* a, Expression* b) {
-    return EffectAnalyzer::canReorder(
-      getPassOptions(), getModule()->features, a, b);
-  }
-
-  // Optimizations that don't yet fit in the pattern DSL, but could be
-  // eventually maybe
-  Expression* handOptimize(Expression* curr) {
-    FeatureSet features = getModule()->features;
-    // if this contains dead code, don't bother trying to optimize it, the type
-    // might change (if might not be unreachable if just one arm is, for
-    // example). this optimization pass focuses on actually executing code. the
-    // only exceptions are control flow changes
-    if (curr->type == Type::unreachable && !curr->is<Break>() &&
-        !curr->is<Switch>() && !curr->is<If>()) {
-      return nullptr;
-    }
-    if (auto* binary = curr->dynCast<Binary>()) {
-      if (isSymmetric(binary)) {
-        canonicalize(binary);
-      }
-    }
-
-    {
-      // TODO: It is an ongoing project to port more transformations to the
-      // match API. Once most of the transformations have been ported, the
-      // `using namespace Match` can be hoisted to function scope and this extra
-      // block scope can be removed.
-      using namespace Match;
-      Builder builder(*getModule());
-      {
-        // try to get rid of (0 - ..), that is, a zero only used to negate an
-        // int. an add of a subtract can be flipped in order to remove it:
-        //   (i32.add
-        //     (i32.sub
-        //       (i32.const 0)
-        //       X
-        //     )
-        //     Y
-        //   )
-        // =>
-        //   (i32.sub
-        //     Y
-        //     X
-        //   )
-        // Note that this reorders X and Y, so we need to be careful about that.
-        Expression *x, *y;
-        Binary* sub;
-        if (matches(curr,
-                    binary(AddInt32,
-                           binary(&sub, SubInt32, i32(0), any(&x)),
-                           any(&y))) &&
-            canReorder(x, y)) {
-          sub->left = y;
-          sub->right = x;
-          return sub;
-        }
-      }
-      {
-        // The flip case is even easier, as no reordering occurs:
-        //   (i32.add
-        //     Y
-        //     (i32.sub
-        //       (i32.const 0)
-        //       X
-        //     )
-        //   )
-        // =>
-        //   (i32.sub
-        //     Y
-        //     X
-        //   )
-        Expression* y;
-        Binary* sub;
-        if (matches(curr,
-                    binary(AddInt32,
-                           any(&y),
-                           binary(&sub, SubInt32, i32(0), any())))) {
-          sub->left = y;
-          return sub;
-        }
-      }
-      {
-        // eqz((signed)x % C_pot)  =>  eqz(x & (abs(C_pot) - 1))
-        Const* c;
-        Binary* inner;
-        if (matches(curr,
-                    unary(Abstract::EqZ,
-                          binary(&inner, Abstract::RemS, any(), ival(&c)))) &&
-            (c->value.isSignedMin() ||
-             Bits::isPowerOf2(c->value.abs().getInteger()))) {
-          inner->op = Abstract::getBinary(c->type, Abstract::And);
-          if (c->value.isSignedMin()) {
-            c->value = Literal::makeSignedMax(c->type);
-          } else {
-            c->value = c->value.abs().sub(Literal::makeOne(c->type));
-          }
-          return curr;
-        }
-      }
-      {
-        // try de-morgan's AND law,
-        //  (eqz X) and (eqz Y) === eqz (X or Y)
-        // Note that the OR and XOR laws do not work here, as these
-        // are not booleans (we could check if they are, but a boolean
-        // would already optimize with the eqz anyhow, unless propagating).
-        // But for AND, the left is true iff X and Y are each all zero bits,
-        // and the right is true if the union of their bits is zero; same.
-        Unary* un;
-        Binary* bin;
-        Expression *x, *y;
-        if (matches(curr,
-                    binary(&bin,
-                           AndInt32,
-                           unary(&un, EqZInt32, any(&x)),
-                           unary(EqZInt32, any(&y))))) {
-          bin->op = OrInt32;
-          bin->left = x;
-          bin->right = y;
-          un->value = bin;
-          return un;
-        }
-      }
-      {
-        // i32.eqz(i32.wrap_i64(x))  =>  i64.eqz(x)
-        //   where maxBits(x) <= 32
-        Unary* inner;
-        Expression* x;
-        if (matches(curr, unary(EqZInt32, unary(&inner, WrapInt64, any(&x)))) &&
-            Bits::getMaxBits(x, this) <= 32) {
-          inner->op = EqZInt64;
-          inner->value = x;
-          return inner;
-        }
-      }
-      {
-        // x <<>> (C & (31 | 63))   ==>   x <<>> C'
-        // x <<>> (y & (31 | 63))   ==>   x <<>> y
-        // where '<<>>':
-        //   '<<', '>>', '>>>'. 'rotl' or 'rotr'
-        BinaryOp op;
-        Const* c;
-        Expression *x, *y;
-
-        // x <<>> C
-        if (matches(curr, binary(&op, any(&x), ival(&c))) &&
-            Abstract::hasAnyShift(op)) {
-          // truncate RHS constant to effective size as:
-          // i32(x) <<>> const(C & 31))
-          // i64(x) <<>> const(C & 63))
-          c->value = c->value.and_(
-            Literal::makeFromInt32(c->type.getByteSize() * 8 - 1, c->type));
-          // x <<>> 0   ==>   x
-          if (c->value.isZero()) {
-            return x;
-          }
-        }
-        if (matches(
-              curr,
-              binary(&op, any(&x), binary(Abstract::And, any(&y), ival(&c)))) &&
-            Abstract::hasAnyShift(op)) {
-          // i32(x) <<>> (y & 31)   ==>   x <<>> y
-          // i64(x) <<>> (y & 63)   ==>   x <<>> y
-          if ((c->type == Type::i32 && (c->value.geti32() & 31) == 31) ||
-              (c->type == Type::i64 && (c->value.geti64() & 63LL) == 63LL)) {
-            curr->cast<Binary>()->right = y;
-            return curr;
-          }
-        }
-      }
-    }
-
-    if (auto* select = curr->dynCast<Select>()) {
-      return optimizeSelect(select);
-    }
-
-    if (auto* binary = curr->dynCast<Binary>()) {
-      if (auto* ext = Properties::getAlmostSignExt(binary)) {
-        Index extraShifts;
-        auto bits = Properties::getAlmostSignExtBits(binary, extraShifts);
-        if (extraShifts == 0) {
-          if (auto* load =
-                Properties::getFallthrough(ext, getPassOptions(), features)
-                  ->dynCast<Load>()) {
-            // pattern match a load of 8 bits and a sign extend using a shl of
-            // 24 then shr_s of 24 as well, etc.
-            if (LoadUtils::canBeSigned(load) &&
-                ((load->bytes == 1 && bits == 8) ||
-                 (load->bytes == 2 && bits == 16))) {
-              // if the value falls through, we can't alter the load, as it
-              // might be captured in a tee
-              if (load->signed_ == true || load == ext) {
-                load->signed_ = true;
-                return ext;
-              }
-            }
-          }
-        }
-        // if the sign-extend input cannot have a sign bit, we don't need it
-        // we also don't need it if it already has an identical-sized sign
-        // extend
-        if (Bits::getMaxBits(ext, this) + extraShifts < bits ||
-            isSignExted(ext, bits)) {
-          return removeAlmostSignExt(binary);
-        }
-      } else if (binary->op == EqInt32 || binary->op == NeInt32) {
-        if (auto* c = binary->right->dynCast<Const>()) {
-          if (auto* ext = Properties::getSignExtValue(binary->left)) {
-            // we are comparing a sign extend to a constant, which means we can
-            // use a cheaper zext
-            auto bits = Properties::getSignExtBits(binary->left);
-            binary->left = makeZeroExt(ext, bits);
-            // when we replace the sign-ext of the non-constant with a zero-ext,
-            // we are forcing the high bits to be all zero, instead of all zero
-            // or all one depending on the sign bit. so we may be changing the
-            // high bits from all one to all zero:
-            //  * if the constant value's higher bits are mixed, then it can't
-            //    be equal anyhow
-            //  * if they are all zero, we may get a false true if the
-            //    non-constant's upper bits were one. this can only happen if
-            //    the non-constant's sign bit is set, so this false true is a
-            //    risk only if the constant's sign bit is set (otherwise,
-            //    false). But a constant with a sign bit but with upper bits
-            //    zero is impossible to be equal to a sign-extended value
-            //    anyhow, so the entire thing is false.
-            //  * if they were all one, we may get a false false, if the only
-            //    difference is in those upper bits. that means we are equal on
-            //    the other bits, including the sign bit. so we can just mask
-            //    off the upper bits in the constant value, in this case,
-            //    forcing them to zero like we do in the zero-extend.
-            int32_t constValue = c->value.geti32();
-            auto upperConstValue = constValue & ~Bits::lowBitMask(bits);
-            uint32_t count = Bits::popCount(upperConstValue);
-            auto constSignBit = constValue & (1 << (bits - 1));
-            if ((count > 0 && count < 32 - bits) ||
-                (constSignBit && count == 0)) {
-              // mixed or [zero upper const bits with sign bit set]; the
-              // compared values can never be identical, so force something
-              // definitely impossible even after zext
-              assert(bits < 32);
-              c->value = Literal(int32_t(0x80000000));
-              // TODO: if no side effects, we can just replace it all with 1 or
-              // 0
-            } else {
-              // otherwise, they are all ones, so we can mask them off as
-              // mentioned before
-              c->value = c->value.and_(Literal(Bits::lowBitMask(bits)));
-            }
-            return binary;
-          }
-        } else if (auto* left = Properties::getSignExtValue(binary->left)) {
-          if (auto* right = Properties::getSignExtValue(binary->right)) {
-            auto bits = Properties::getSignExtBits(binary->left);
-            if (Properties::getSignExtBits(binary->right) == bits) {
-              // we are comparing two sign-exts with the same bits, so we may as
-              // well replace both with cheaper zexts
-              binary->left = makeZeroExt(left, bits);
-              binary->right = makeZeroExt(right, bits);
-              return binary;
-            }
-          } else if (auto* load = binary->right->dynCast<Load>()) {
-            // we are comparing a load to a sign-ext, we may be able to switch
-            // to zext
-            auto leftBits = Properties::getSignExtBits(binary->left);
-            if (load->signed_ && leftBits == load->bytes * 8) {
-              load->signed_ = false;
-              binary->left = makeZeroExt(left, leftBits);
-              return binary;
-            }
-          }
-        } else if (auto* load = binary->left->dynCast<Load>()) {
-          if (auto* right = Properties::getSignExtValue(binary->right)) {
-            // we are comparing a load to a sign-ext, we may be able to switch
-            // to zext
-            auto rightBits = Properties::getSignExtBits(binary->right);
-            if (load->signed_ && rightBits == load->bytes * 8) {
-              load->signed_ = false;
-              binary->right = makeZeroExt(right, rightBits);
-              return binary;
-            }
-          }
-        }
-        // note that both left and right may be consts, but then we let
-        // precompute compute the constant result
-      } else if (binary->op == AddInt32) {
-        if (auto* ret = optimizeAddedConstants(binary)) {
-          return ret;
-        }
-      } else if (binary->op == SubInt32) {
-        if (auto* ret = optimizeAddedConstants(binary)) {
-          return ret;
-        }
-      }
-      // a bunch of operations on a constant right side can be simplified
-      if (auto* right = binary->right->dynCast<Const>()) {
-        if (binary->op == AndInt32) {
-          auto mask = right->value.geti32();
-          // and with -1 does nothing (common in asm.js output)
-          if (mask == -1) {
-            return binary->left;
-          }
-          // small loads do not need to be masked, the load itself masks
-          if (auto* load = binary->left->dynCast<Load>()) {
-            if ((load->bytes == 1 && mask == 0xff) ||
-                (load->bytes == 2 && mask == 0xffff)) {
-              load->signed_ = false;
-              return binary->left;
-            }
-          } else if (auto maskedBits = Bits::getMaskedBits(mask)) {
-            if (Bits::getMaxBits(binary->left, this) <= maskedBits) {
-              // a mask of lower bits is not needed if we are already smaller
-              return binary->left;
-            }
-          }
-        }
-        // some math operations have trivial results
-        if (auto* ret = optimizeWithConstantOnRight(binary)) {
-          return ret;
-        }
-        // the square of some operations can be merged
-        if (auto* left = binary->left->dynCast<Binary>()) {
-          if (left->op == binary->op) {
-            if (auto* leftRight = left->right->dynCast<Const>()) {
-              if (left->op == AndInt32) {
-                leftRight->value = leftRight->value.and_(right->value);
-                return left;
-              } else if (left->op == OrInt32) {
-                leftRight->value = leftRight->value.or_(right->value);
-                return left;
-              } else if (left->op == ShlInt32 || left->op == ShrUInt32 ||
-                         left->op == ShrSInt32 || left->op == ShlInt64 ||
-                         left->op == ShrUInt64 || left->op == ShrSInt64) {
-                // shifts only use an effective amount from the constant, so
-                // adding must be done carefully
-                auto total = Bits::getEffectiveShifts(leftRight) +
-                             Bits::getEffectiveShifts(right);
-                if (total == Bits::getEffectiveShifts(total, right->type)) {
-                  // no overflow, we can do this
-                  leftRight->value = Literal::makeFromInt32(total, right->type);
-                  return left;
-                } // TODO: handle overflows
-              }
-            }
-          }
-        }
-        if (right->type == Type::i32) {
-          BinaryOp op;
-          int32_t c = right->value.geti32();
-          // First, try to lower signed operations to unsigned if that is
-          // possible. Some unsigned operations like div_u or rem_u are usually
-          // faster on VMs. Also this opens more possibilities for further
-          // simplifications afterwards.
-          if (c >= 0 &&
-              (op = makeUnsignedBinaryOp(binary->op)) != InvalidBinary &&
-              Bits::getMaxBits(binary->left, this) <= 31) {
-            binary->op = op;
-          }
-          if (c < 0 && c > std::numeric_limits<int32_t>::min() &&
-              binary->op == DivUInt32) {
-            // u32(x) / C   ==>   u32(x) >= C  iff C > 2^31
-            // We avoid applying this for C == 2^31 due to conflict
-            // with other rule which transform to more prefereble
-            // right shift operation.
-            binary->op = c == -1 ? EqInt32 : GeUInt32;
-            return binary;
-          }
-          if (Bits::isPowerOf2((uint32_t)c)) {
-            switch (binary->op) {
-              case MulInt32:
-                return optimizePowerOf2Mul(binary, (uint32_t)c);
-              case RemUInt32:
-                return optimizePowerOf2URem(binary, (uint32_t)c);
-              case DivUInt32:
-                return optimizePowerOf2UDiv(binary, (uint32_t)c);
-              default:
-                break;
-            }
-          }
-        }
-        if (right->type == Type::i64) {
-          BinaryOp op;
-          int64_t c = right->value.geti64();
-          // See description above for Type::i32
-          if (c >= 0 &&
-              (op = makeUnsignedBinaryOp(binary->op)) != InvalidBinary &&
-              Bits::getMaxBits(binary->left, this) <= 63) {
-            binary->op = op;
-          }
-          if (getPassOptions().shrinkLevel == 0 && c < 0 &&
-              c > std::numeric_limits<int64_t>::min() &&
-              binary->op == DivUInt64) {
-            // u64(x) / C   ==>   u64(u64(x) >= C)  iff C > 2^63
-            // We avoid applying this for C == 2^31 due to conflict
-            // with other rule which transform to more prefereble
-            // right shift operation.
-            // And apply this only for shrinkLevel == 0 due to it
-            // increasing size by one byte.
-            binary->op = c == -1LL ? EqInt64 : GeUInt64;
-            binary->type = Type::i32;
-            return Builder(*getModule()).makeUnary(ExtendUInt32, binary);
-          }
-          if (Bits::isPowerOf2((uint64_t)c)) {
-            switch (binary->op) {
-              case MulInt64:
-                return optimizePowerOf2Mul(binary, (uint64_t)c);
-              case RemUInt64:
-                return optimizePowerOf2URem(binary, (uint64_t)c);
-              case DivUInt64:
-                return optimizePowerOf2UDiv(binary, (uint64_t)c);
-              default:
-                break;
-            }
-          }
-        }
-      }
-      // a bunch of operations on a constant left side can be simplified
-      if (binary->left->is<Const>()) {
-        if (auto* ret = optimizeWithConstantOnLeft(binary)) {
-          return ret;
-        }
-      }
-      // bitwise operations
-      // for and and or, we can potentially conditionalize
-      if (binary->op == AndInt32 || binary->op == OrInt32) {
-        if (auto* ret = conditionalizeExpensiveOnBitwise(binary)) {
-          return ret;
-        }
-      }
-      // for or, we can potentially combine
-      if (binary->op == OrInt32) {
-        if (auto* ret = combineOr(binary)) {
-          return ret;
-        }
-      }
-      // relation/comparisons allow for math optimizations
-      if (binary->isRelational()) {
-        if (auto* ret = optimizeRelational(binary)) {
-          return ret;
-        }
-      }
-      // finally, try more expensive operations on the binary in
-      // the case that they have no side effects
-      if (!effects(binary->left).hasSideEffects()) {
-        if (ExpressionAnalyzer::equal(binary->left, binary->right)) {
-          if (auto* ret = optimizeBinaryWithEqualEffectlessChildren(binary)) {
-            return ret;
-          }
-        }
-      }
-
-      if (auto* ret = deduplicateBinary(binary)) {
-        return ret;
-      }
-    } else if (auto* unary = curr->dynCast<Unary>()) {
-      if (unary->op == EqZInt32) {
-        if (auto* inner = unary->value->dynCast<Binary>()) {
-          // Try to invert a relational operation using De Morgan's law
-          auto op = invertBinaryOp(inner->op);
-          if (op != InvalidBinary) {
-            inner->op = op;
-            return inner;
-          }
-        }
-        // eqz of a sign extension can be of zero-extension
-        if (auto* ext = Properties::getSignExtValue(unary->value)) {
-          // we are comparing a sign extend to a constant, which means we can
-          // use a cheaper zext
-          auto bits = Properties::getSignExtBits(unary->value);
-          unary->value = makeZeroExt(ext, bits);
-          return unary;
-        }
-      }
-
-      if (auto* ret = deduplicateUnary(unary)) {
-        return ret;
-      }
-    } else if (auto* set = curr->dynCast<GlobalSet>()) {
-      // optimize out a set of a get
-      auto* get = set->value->dynCast<GlobalGet>();
-      if (get && get->name == set->name) {
-        ExpressionManipulator::nop(curr);
-      }
-    } else if (auto* iff = curr->dynCast<If>()) {
-      iff->condition = optimizeBoolean(iff->condition);
-      if (iff->ifFalse) {
-        if (auto* unary = iff->condition->dynCast<Unary>()) {
-          if (unary->op == EqZInt32) {
-            // flip if-else arms to get rid of an eqz
-            iff->condition = unary->value;
-            std::swap(iff->ifTrue, iff->ifFalse);
-          }
-        }
-        if (iff->condition->type != Type::unreachable &&
-            ExpressionAnalyzer::equal(iff->ifTrue, iff->ifFalse)) {
-          // sides are identical, fold
-          // if we can replace the if with one arm, and no side effects in the
-          // condition, do that
-          auto needCondition = effects(iff->condition).hasSideEffects();
-          auto isSubType = Type::isSubType(iff->ifTrue->type, iff->type);
-          if (isSubType && !needCondition) {
-            return iff->ifTrue;
-          } else {
-            Builder builder(*getModule());
-            if (isSubType) {
-              return builder.makeSequence(builder.makeDrop(iff->condition),
-                                          iff->ifTrue);
-            } else {
-              // the types diff. as the condition is reachable, that means the
-              // if must be concrete while the arm is not
-              assert(iff->type.isConcrete() &&
-                     iff->ifTrue->type == Type::unreachable);
-              // emit a block with a forced type
-              auto* ret = builder.makeBlock();
-              if (needCondition) {
-                ret->list.push_back(builder.makeDrop(iff->condition));
-              }
-              ret->list.push_back(iff->ifTrue);
-              ret->finalize(iff->type);
-              return ret;
-            }
-          }
-        }
-      }
-    } else if (auto* br = curr->dynCast<Break>()) {
-      if (br->condition) {
-        br->condition = optimizeBoolean(br->condition);
-      }
-    } else if (auto* load = curr->dynCast<Load>()) {
-      optimizeMemoryAccess(load->ptr, load->offset);
-    } else if (auto* store = curr->dynCast<Store>()) {
-      optimizeMemoryAccess(store->ptr, store->offset);
-      // stores of fewer bits truncates anyhow
-      if (auto* binary = store->value->dynCast<Binary>()) {
-        if (binary->op == AndInt32) {
-          if (auto* right = binary->right->dynCast<Const>()) {
-            if (right->type == Type::i32) {
-              auto mask = right->value.geti32();
-              if ((store->bytes == 1 && mask == 0xff) ||
-                  (store->bytes == 2 && mask == 0xffff)) {
-                store->value = binary->left;
-              }
-            }
-          }
-        } else if (auto* ext = Properties::getSignExtValue(binary)) {
-          // if sign extending the exact bit size we store, we can skip the
-          // extension if extending something bigger, then we just alter bits we
-          // don't save anyhow
-          if (Properties::getSignExtBits(binary) >= Index(store->bytes) * 8) {
-            store->value = ext;
-          }
-        }
-      } else if (auto* unary = store->value->dynCast<Unary>()) {
-        if (unary->op == WrapInt64) {
-          // instead of wrapping to 32, just store some of the bits in the i64
-          store->valueType = Type::i64;
-          store->value = unary->value;
-        }
-      }
-    } else if (auto* memCopy = curr->dynCast<MemoryCopy>()) {
-      assert(features.hasBulkMemory());
-      if (auto* ret = optimizeMemoryCopy(memCopy)) {
-        return ret;
-      }
-    }
-    return nullptr;
-  }
-
-  Index getMaxBitsForLocal(LocalGet* get) {
-    // check what we know about the local
-    return localInfo[get->index].maxBits;
-  }
-
-private:
-  // Information about our locals
-  std::vector<LocalInfo> localInfo;
-
-  // Canonicalizing the order of a symmetric binary helps us
-  // write more concise pattern matching code elsewhere.
-  void canonicalize(Binary* binary) {
-    assert(isSymmetric(binary));
-    auto swap = [&]() {
-      assert(canReorder(binary->left, binary->right));
-      std::swap(binary->left, binary->right);
-    };
-    auto maybeSwap = [&]() {
-      if (canReorder(binary->left, binary->right)) {
-        swap();
-      }
-    };
-    // Prefer a const on the right.
-    if (binary->left->is<Const>() && !binary->right->is<Const>()) {
-      return swap();
-    }
-    if (binary->right->is<Const>()) {
-      return;
-    }
-    // Prefer a get on the right.
-    if (binary->left->is<LocalGet>() && !binary->right->is<LocalGet>()) {
-      return maybeSwap();
-    }
-    // Sort by the node id type, if different.
-    if (binary->left->_id != binary->right->_id) {
-      if (binary->left->_id > binary->right->_id) {
-        return maybeSwap();
-      }
-      return;
-    }
-    // If the children have the same node id, we have to go deeper.
-    if (auto* left = binary->left->dynCast<Unary>()) {
-      auto* right = binary->right->cast<Unary>();
-      if (left->op > right->op) {
-        return maybeSwap();
-      }
-    }
-    if (auto* left = binary->left->dynCast<Binary>()) {
-      auto* right = binary->right->cast<Binary>();
-      if (left->op > right->op) {
-        return maybeSwap();
-      }
-    }
-    if (auto* left = binary->left->dynCast<LocalGet>()) {
-      auto* right = binary->right->cast<LocalGet>();
-      if (left->index > right->index) {
-        return maybeSwap();
-      }
-    }
-  }
-
-  // Optimize given that the expression is flowing into a boolean context
-  Expression* optimizeBoolean(Expression* boolean) {
-    // TODO use a general getFallthroughs
-    if (auto* unary = boolean->dynCast<Unary>()) {
-      if (unary) {
-        if (unary->op == EqZInt32) {
-          auto* unary2 = unary->value->dynCast<Unary>();
-          if (unary2 && unary2->op == EqZInt32) {
-            // double eqz
-            return unary2->value;
-          }
-          if (auto* binary = unary->value->dynCast<Binary>()) {
-            // !(x <=> y)   ==>   x <!=> y
-            auto op = invertBinaryOp(binary->op);
-            if (op != InvalidBinary) {
-              binary->op = op;
-              return binary;
-            }
-          }
-        }
-      }
-    } else if (auto* binary = boolean->dynCast<Binary>()) {
-      if (binary->op == SubInt32) {
-        if (auto* c = binary->left->dynCast<Const>()) {
-          if (c->value.geti32() == 0) {
-            // bool(0 - x)   ==>   bool(x)
-            return binary->right;
-          }
-        }
-      } else if (binary->op == OrInt32) {
-        // an or flowing into a boolean context can consider each input as
-        // boolean
-        binary->left = optimizeBoolean(binary->left);
-        binary->right = optimizeBoolean(binary->right);
-      } else if (binary->op == NeInt32) {
-        if (auto* c = binary->right->dynCast<Const>()) {
-          // x != 0 is just x if it's used as a bool
-          if (c->value.geti32() == 0) {
-            return binary->left;
-          }
-          // TODO: Perhaps use it for separate final pass???
-          // x != -1   ==>    x ^ -1
-          // if (num->value.geti32() == -1) {
-          //   binary->op = XorInt32;
-          //   return binary;
-          // }
-        }
-      }
-      if (auto* ext = Properties::getSignExtValue(binary)) {
-        // use a cheaper zero-extent, we just care about the boolean value
-        // anyhow
-        return makeZeroExt(ext, Properties::getSignExtBits(binary));
-      }
-    } else if (auto* block = boolean->dynCast<Block>()) {
-      if (block->type == Type::i32 && block->list.size() > 0) {
-        block->list.back() = optimizeBoolean(block->list.back());
-      }
-    } else if (auto* iff = boolean->dynCast<If>()) {
-      if (iff->type == Type::i32) {
-        iff->ifTrue = optimizeBoolean(iff->ifTrue);
-        iff->ifFalse = optimizeBoolean(iff->ifFalse);
-      }
-    } else if (auto* select = boolean->dynCast<Select>()) {
-      select->ifTrue = optimizeBoolean(select->ifTrue);
-      select->ifFalse = optimizeBoolean(select->ifFalse);
-    } else if (auto* tryy = boolean->dynCast<Try>()) {
-      if (tryy->type == Type::i32) {
-        tryy->body = optimizeBoolean(tryy->body);
-        tryy->catchBody = optimizeBoolean(tryy->catchBody);
-      }
-    }
-    // TODO: recurse into br values?
-    return boolean;
-  }
-
-  Expression* optimizeSelect(Select* curr) {
-    using namespace Match;
-    Builder builder(*getModule());
-    curr->condition = optimizeBoolean(curr->condition);
-    {
-      // Constant condition, we can just pick the correct side (barring side
-      // effects)
-      Expression *ifTrue, *ifFalse;
-      if (matches(curr, select(pure(&ifTrue), any(&ifFalse), i32(0)))) {
-        return ifFalse;
-      }
-      if (matches(curr, select(any(&ifTrue), any(&ifFalse), i32(0)))) {
-        return builder.makeSequence(builder.makeDrop(ifTrue), ifFalse);
-      }
-      int32_t cond;
-      if (matches(curr, select(any(&ifTrue), pure(&ifFalse), i32(&cond)))) {
-        // The condition must be non-zero because a zero would have matched one
-        // of the previous patterns.
-        assert(cond != 0);
-        return ifTrue;
-      }
-      // Don't bother when `ifFalse` isn't pure - we would need to reverse the
-      // order using a temp local, which would be bad
-    }
-    {
-      // Flip select to remove eqz if we can reorder
-      Select* s;
-      Expression *ifTrue, *ifFalse, *c;
-      if (matches(
-            curr,
-            select(
-              &s, any(&ifTrue), any(&ifFalse), unary(EqZInt32, any(&c)))) &&
-          canReorder(ifTrue, ifFalse)) {
-        s->ifTrue = ifFalse;
-        s->ifFalse = ifTrue;
-        s->condition = c;
-      }
-    }
-    {
-      // Simplify selects between 0 and 1
-      Expression* c;
-      bool reversed = matches(curr, select(ival(0), ival(1), any(&c)));
-      if (reversed || matches(curr, select(ival(1), ival(0), any(&c)))) {
-        if (reversed) {
-          c = optimizeBoolean(builder.makeUnary(EqZInt32, c));
-        }
-        if (!Properties::emitsBoolean(c)) {
-          // cond ? 1 : 0 ==> !!cond
-          c = builder.makeUnary(EqZInt32, builder.makeUnary(EqZInt32, c));
-        }
-        return curr->type == Type::i64 ? builder.makeUnary(ExtendUInt32, c) : c;
-      }
-    }
-    {
-      // Sides are identical, fold
-      Expression *ifTrue, *ifFalse, *c;
-      if (matches(curr, select(any(&ifTrue), any(&ifFalse), any(&c))) &&
-          ExpressionAnalyzer::equal(ifTrue, ifFalse)) {
-        auto value = effects(ifTrue);
-        if (value.hasSideEffects()) {
-          // At best we don't need the condition, but need to execute the
-          // value twice. a block is larger than a select by 2 bytes, and we
-          // must drop one value, so 3, while we save the condition, so it's
-          // not clear this is worth it, TODO
-        } else {
-          // value has no side effects
-          auto condition = effects(c);
-          if (!condition.hasSideEffects()) {
-            return ifTrue;
-          } else {
-            // The condition is last, so we need a new local, and it may be a
-            // bad idea to use a block like we do for an if. Do it only if we
-            // can reorder
-            if (!condition.invalidates(value)) {
-              return builder.makeSequence(builder.makeDrop(c), ifTrue);
-            }
-          }
-        }
-      }
-    }
-    return nullptr;
-  }
-
-  // find added constants in an expression tree, including multiplied/shifted,
-  // and combine them note that we ignore division/shift-right, as rounding
-  // makes this nonlinear, so not a valid opt
-  Expression* optimizeAddedConstants(Binary* binary) {
-    uint32_t constant = 0;
-    std::vector<Const*> constants;
-
-    struct SeekState {
-      Expression* curr;
-      int mul;
-      SeekState(Expression* curr, int mul) : curr(curr), mul(mul) {}
-    };
-    std::vector<SeekState> seekStack;
-    seekStack.emplace_back(binary, 1);
-    while (!seekStack.empty()) {
-      auto state = seekStack.back();
-      seekStack.pop_back();
-      auto curr = state.curr;
-      auto mul = state.mul;
-      if (auto* c = curr->dynCast<Const>()) {
-        uint32_t value = c->value.geti32();
-        if (value != 0) {
-          constant += value * mul;
-          constants.push_back(c);
-        }
-        continue;
-      } else if (auto* binary = curr->dynCast<Binary>()) {
-        if (binary->op == AddInt32) {
-          seekStack.emplace_back(binary->right, mul);
-          seekStack.emplace_back(binary->left, mul);
-          continue;
-        } else if (binary->op == SubInt32) {
-          // if the left is a zero, ignore it, it's how we negate ints
-          auto* left = binary->left->dynCast<Const>();
-          seekStack.emplace_back(binary->right, -mul);
-          if (!left || left->value.geti32() != 0) {
-            seekStack.emplace_back(binary->left, mul);
-          }
-          continue;
-        } else if (binary->op == ShlInt32) {
-          if (auto* c = binary->right->dynCast<Const>()) {
-            seekStack.emplace_back(
-              binary->left, mul * Bits::pow2(Bits::getEffectiveShifts(c)));
-            continue;
-          }
-        } else if (binary->op == MulInt32) {
-          if (auto* c = binary->left->dynCast<Const>()) {
-            seekStack.emplace_back(binary->right, mul * c->value.geti32());
-            continue;
-          } else if (auto* c = binary->right->dynCast<Const>()) {
-            seekStack.emplace_back(binary->left, mul * c->value.geti32());
-            continue;
-          }
-        }
-      }
-    };
-    // find all factors
-    if (constants.size() <= 1) {
-      // nothing much to do, except for the trivial case of adding/subbing a
-      // zero
-      if (auto* c = binary->right->dynCast<Const>()) {
-        if (c->value.geti32() == 0) {
-          return binary->left;
-        }
-      }
-      return nullptr;
-    }
-    // wipe out all constants, we'll replace with a single added one
-    for (auto* c : constants) {
-      c->value = Literal(int32_t(0));
-    }
-    // remove added/subbed zeros
-    struct ZeroRemover : public PostWalker<ZeroRemover> {
-      // TODO: we could save the binarys and costs we drop, and reuse them later
-
-      PassOptions& passOptions;
-
-      ZeroRemover(PassOptions& passOptions) : passOptions(passOptions) {}
-
-      void visitBinary(Binary* curr) {
-        FeatureSet features = getModule()->features;
-        auto* left = curr->left->dynCast<Const>();
-        auto* right = curr->right->dynCast<Const>();
-        if (curr->op == AddInt32) {
-          if (left && left->value.geti32() == 0) {
-            replaceCurrent(curr->right);
-            return;
-          }
-          if (right && right->value.geti32() == 0) {
-            replaceCurrent(curr->left);
-            return;
-          }
-        } else if (curr->op == SubInt32) {
-          // we must leave a left zero, as it is how we negate ints
-          if (right && right->value.geti32() == 0) {
-            replaceCurrent(curr->left);
-            return;
-          }
-        } else if (curr->op == ShlInt32) {
-          // shifting a 0 is a 0, or anything by 0 has no effect, all unless the
-          // shift has side effects
-          if (((left && left->value.geti32() == 0) ||
-               (right && Bits::getEffectiveShifts(right) == 0)) &&
-              !EffectAnalyzer(passOptions, features, curr->right)
-                 .hasSideEffects()) {
-            replaceCurrent(curr->left);
-            return;
-          }
-        } else if (curr->op == MulInt32) {
-          // multiplying by zero is a zero, unless the other side has side
-          // effects
-          if (left && left->value.geti32() == 0 &&
-              !EffectAnalyzer(passOptions, features, curr->right)
-                 .hasSideEffects()) {
-            replaceCurrent(left);
-            return;
-          }
-          if (right && right->value.geti32() == 0 &&
-              !EffectAnalyzer(passOptions, features, curr->left)
-                 .hasSideEffects()) {
-            replaceCurrent(right);
-            return;
-          }
-        }
-      }
-    };
-    Expression* walked = binary;
-    ZeroRemover remover(getPassOptions());
-    remover.setModule(getModule());
-    remover.walk(walked);
-    if (constant == 0) {
-      return walked; // nothing more to do
-    }
-    if (auto* c = walked->dynCast<Const>()) {
-      assert(c->value.geti32() == 0);
-      c->value = Literal(constant);
-      return c;
-    }
-    Builder builder(*getModule());
-    return builder.makeBinary(
-      AddInt32, walked, builder.makeConst(Literal(constant)));
-  }
-
-  //   expensive1 | expensive2 can be turned into expensive1 ? 1 : expensive2,
-  //   and expensive | cheap     can be turned into cheap     ? 1 : expensive,
-  // so that we can avoid one expensive computation, if it has no side effects.
-  Expression* conditionalizeExpensiveOnBitwise(Binary* binary) {
-    // this operation can increase code size, so don't always do it
-    auto& options = getPassRunner()->options;
-    if (options.optimizeLevel < 2 || options.shrinkLevel > 0) {
-      return nullptr;
-    }
-    const auto MIN_COST = 7;
-    assert(binary->op == AndInt32 || binary->op == OrInt32);
-    if (binary->right->is<Const>()) {
-      return nullptr; // trivial
-    }
-    // bitwise logical operator on two non-numerical values, check if they are
-    // boolean
-    auto* left = binary->left;
-    auto* right = binary->right;
-    if (!Properties::emitsBoolean(left) || !Properties::emitsBoolean(right)) {
-      return nullptr;
-    }
-    auto leftEffects = effects(left);
-    auto rightEffects = effects(right);
-    auto leftHasSideEffects = leftEffects.hasSideEffects();
-    auto rightHasSideEffects = rightEffects.hasSideEffects();
-    if (leftHasSideEffects && rightHasSideEffects) {
-      return nullptr; // both must execute
-    }
-    // canonicalize with side effects, if any, happening on the left
-    if (rightHasSideEffects) {
-      if (CostAnalyzer(left).cost < MIN_COST) {
-        return nullptr; // avoidable code is too cheap
-      }
-      if (leftEffects.invalidates(rightEffects)) {
-        return nullptr; // cannot reorder
-      }
-      std::swap(left, right);
-    } else if (leftHasSideEffects) {
-      if (CostAnalyzer(right).cost < MIN_COST) {
-        return nullptr; // avoidable code is too cheap
-      }
-    } else {
-      // no side effects, reorder based on cost estimation
-      auto leftCost = CostAnalyzer(left).cost;
-      auto rightCost = CostAnalyzer(right).cost;
-      if (std::max(leftCost, rightCost) < MIN_COST) {
-        return nullptr; // avoidable code is too cheap
-      }
-      // canonicalize with expensive code on the right
-      if (leftCost > rightCost) {
-        std::swap(left, right);
-      }
-    }
-    // worth it! perform conditionalization
-    Builder builder(*getModule());
-    if (binary->op == OrInt32) {
-      return builder.makeIf(
-        left, builder.makeConst(Literal(int32_t(1))), right);
-    } else { // &
-      return builder.makeIf(
-        left, right, builder.makeConst(Literal(int32_t(0))));
-    }
-  }
-
-  // We can combine `or` operations, e.g.
-  //   (x > y) | (x == y)    ==>    x >= y
-  Expression* combineOr(Binary* binary) {
-    assert(binary->op == OrInt32);
-    if (auto* left = binary->left->dynCast<Binary>()) {
-      if (auto* right = binary->right->dynCast<Binary>()) {
-        if (left->op != right->op &&
-            ExpressionAnalyzer::equal(left->left, right->left) &&
-            ExpressionAnalyzer::equal(left->right, right->right) &&
-            !effects(left->left).hasSideEffects() &&
-            !effects(left->right).hasSideEffects()) {
-          switch (left->op) {
-            //   (x > y) | (x == y)    ==>    x >= y
-            case EqInt32: {
-              if (right->op == GtSInt32) {
-                left->op = GeSInt32;
-                return left;
-              }
-              break;
-            }
-            default: {
-            }
-          }
-        }
-      }
-    }
-    return nullptr;
-  }
-
-  // fold constant factors into the offset
-  void optimizeMemoryAccess(Expression*& ptr, Address& offset) {
-    // ptr may be a const, but it isn't worth folding that in (we still have a
-    // const); in fact, it's better to do the opposite for gzip purposes as well
-    // as for readability.
-    auto* last = ptr->dynCast<Const>();
-    if (last) {
-      uint64_t value64 = last->value.getInteger();
-      uint64_t offset64 = offset;
-      if (getModule()->memory.is64()) {
-        last->value = Literal(int64_t(value64 + offset64));
-        offset = 0;
-      } else {
-        // don't do this if it would wrap the pointer
-        if (value64 <= uint64_t(std::numeric_limits<int32_t>::max()) &&
-            offset64 <= uint64_t(std::numeric_limits<int32_t>::max()) &&
-            value64 + offset64 <=
-              uint64_t(std::numeric_limits<int32_t>::max())) {
-          last->value = Literal(int32_t(value64 + offset64));
-          offset = 0;
-        }
-      }
-    }
-  }
-
-  // Optimize a multiply by a power of two on the right, which
-  // can be a shift.
-  // This doesn't shrink code size, and VMs likely optimize it anyhow,
-  // but it's still worth doing since
-  //  * Often shifts are more common than muls.
-  //  * The constant is smaller.
-  template<typename T> Expression* optimizePowerOf2Mul(Binary* binary, T c) {
-    static_assert(std::is_same<T, uint32_t>::value ||
-                    std::is_same<T, uint64_t>::value,
-                  "type mismatch");
-    auto shifts = Bits::countTrailingZeroes(c);
-    binary->op = std::is_same<T, uint32_t>::value ? ShlInt32 : ShlInt64;
-    binary->right->cast<Const>()->value = Literal(static_cast<T>(shifts));
-    return binary;
-  }
-
-  // Optimize an unsigned divide / remainder by a power of two on the right
-  // This doesn't shrink code size, and VMs likely optimize it anyhow,
-  // but it's still worth doing since
-  //  * Usually ands are more common than urems.
-  //  * The constant is slightly smaller.
-  template<typename T> Expression* optimizePowerOf2UDiv(Binary* binary, T c) {
-    static_assert(std::is_same<T, uint32_t>::value ||
-                    std::is_same<T, uint64_t>::value,
-                  "type mismatch");
-    auto shifts = Bits::countTrailingZeroes(c);
-    binary->op = std::is_same<T, uint32_t>::value ? ShrUInt32 : ShrUInt64;
-    binary->right->cast<Const>()->value = Literal(static_cast<T>(shifts));
-    return binary;
-  }
-
-  template<typename T> Expression* optimizePowerOf2URem(Binary* binary, T c) {
-    static_assert(std::is_same<T, uint32_t>::value ||
-                    std::is_same<T, uint64_t>::value,
-                  "type mismatch");
-    binary->op = std::is_same<T, uint32_t>::value ? AndInt32 : AndInt64;
-    binary->right->cast<Const>()->value = Literal(c - 1);
-    return binary;
-  }
-
-  Expression* makeZeroExt(Expression* curr, int32_t bits) {
-    Builder builder(*getModule());
-    return builder.makeBinary(
-      AndInt32, curr, builder.makeConst(Literal(Bits::lowBitMask(bits))));
-  }
-
-  // given an "almost" sign extend - either a proper one, or it
-  // has too many shifts left - we remove the sign extend. If there are
-  // too many shifts, we split the shifts first, so this removes the
-  // two sign extend shifts and adds one (smaller one)
-  Expression* removeAlmostSignExt(Binary* outer) {
-    auto* inner = outer->left->cast<Binary>();
-    auto* outerConst = outer->right->cast<Const>();
-    auto* innerConst = inner->right->cast<Const>();
-    auto* value = inner->left;
-    if (outerConst->value == innerConst->value) {
-      return value;
-    }
-    // add a shift, by reusing the existing node
-    innerConst->value = innerConst->value.sub(outerConst->value);
-    return inner;
-  }
-
-  // check if an expression is already sign-extended
-  bool isSignExted(Expression* curr, Index bits) {
-    if (Properties::getSignExtValue(curr)) {
-      return Properties::getSignExtBits(curr) == bits;
-    }
-    if (auto* get = curr->dynCast<LocalGet>()) {
-      // check what we know about the local
-      return localInfo[get->index].signExtedBits == bits;
-    }
-    return false;
-  }
-
-  // optimize trivial math operations, given that the right side of a binary
-  // is a constant
-  Expression* optimizeWithConstantOnRight(Binary* curr) {
-    using namespace Match;
-    Builder builder(*getModule());
-    Expression* left;
-    auto* right = curr->right->cast<Const>();
-    auto type = curr->right->type;
-
-    // Operations on zero
-    if (matches(curr, binary(Abstract::Shl, any(&left), ival(0))) ||
-        matches(curr, binary(Abstract::ShrU, any(&left), ival(0))) ||
-        matches(curr, binary(Abstract::ShrS, any(&left), ival(0))) ||
-        matches(curr, binary(Abstract::Or, any(&left), ival(0))) ||
-        matches(curr, binary(Abstract::Xor, any(&left), ival(0)))) {
-      return left;
-    }
-    if (matches(curr, binary(Abstract::Mul, pure(&left), ival(0))) ||
-        matches(curr, binary(Abstract::And, pure(&left), ival(0)))) {
-      return right;
-    }
-    // x == 0   ==>   eqz x
-    if (matches(curr, binary(Abstract::Eq, any(&left), ival(0)))) {
-      return builder.makeUnary(Abstract::getUnary(type, Abstract::EqZ), left);
-    }
-    // Operations on one
-    // (signed)x % 1   ==>   0
-    if (matches(curr, binary(Abstract::RemS, pure(&left), ival(1)))) {
-      right->value = Literal::makeZero(type);
-      return right;
-    }
-    // (signed)x % C_pot != 0   ==>  (x & (abs(C_pot) - 1)) != 0
-    {
-      Const* c;
-      Binary* inner;
-      if (matches(curr,
-                  binary(Abstract::Ne,
-                         binary(&inner, Abstract::RemS, any(), ival(&c)),
-                         ival(0))) &&
-          (c->value.isSignedMin() ||
-           Bits::isPowerOf2(c->value.abs().getInteger()))) {
-        inner->op = Abstract::getBinary(c->type, Abstract::And);
-        if (c->value.isSignedMin()) {
-          c->value = Literal::makeSignedMax(c->type);
-        } else {
-          c->value = c->value.abs().sub(Literal::makeOne(c->type));
-        }
-        return curr;
-      }
-    }
-    // bool(x) | 1  ==>  1
-    if (matches(curr, binary(Abstract::Or, pure(&left), ival(1))) &&
-        Bits::getMaxBits(left, this) == 1) {
-      return right;
-    }
-    // bool(x) & 1  ==>  bool(x)
-    if (matches(curr, binary(Abstract::And, any(&left), ival(1))) &&
-        Bits::getMaxBits(left, this) == 1) {
-      return left;
-    }
-    // bool(x) == 1  ==>  bool(x)
-    if (matches(curr, binary(EqInt32, any(&left), i32(1))) &&
-        Bits::getMaxBits(left, this) == 1) {
-      return left;
-    }
-    // i64(bool(x)) == 1  ==>  i32(bool(x))
-    // i64(bool(x)) != 0  ==>  i32(bool(x))
-    if ((matches(curr, binary(EqInt64, any(&left), i64(1))) ||
-         matches(curr, binary(NeInt64, any(&left), i64(0)))) &&
-        Bits::getMaxBits(left, this) == 1) {
-      return builder.makeUnary(WrapInt64, left);
-    }
-    // bool(x) != 1  ==>  !bool(x)
-    if (matches(curr, binary(Abstract::Ne, any(&left), ival(1))) &&
-        Bits::getMaxBits(curr->left, this) == 1) {
-      return builder.makeUnary(Abstract::getUnary(type, Abstract::EqZ), left);
-    }
-
-    // Operations on all 1s
-    // x & -1   ==>   x
-    if (matches(curr, binary(Abstract::And, any(&left), ival(-1)))) {
-      return left;
-    }
-    // x | -1   ==>   -1
-    if (matches(curr, binary(Abstract::Or, pure(&left), ival(-1)))) {
-      return right;
-    }
-    // (signed)x % -1   ==>   0
-    if (matches(curr, binary(Abstract::RemS, pure(&left), ival(-1)))) {
-      right->value = Literal::makeZero(type);
-      return right;
-    }
-    // (unsigned)x > -1   ==>   0
-    if (matches(curr, binary(Abstract::GtU, pure(&left), ival(-1)))) {
-      right->value = Literal::makeZero(Type::i32);
-      right->type = Type::i32;
-      return right;
-    }
-    // (unsigned)x < -1   ==>   x != -1
-    // Friendlier to JS emitting as we don't need to write an unsigned -1 value
-    // which is large.
-    if (matches(curr, binary(Abstract::LtU, any(), ival(-1)))) {
-      curr->op = Abstract::getBinary(type, Abstract::Ne);
-      return curr;
-    }
-    // x * -1   ==>   0 - x
-    if (matches(curr, binary(Abstract::Mul, any(&left), ival(-1)))) {
-      right->value = Literal::makeZero(type);
-      curr->op = Abstract::getBinary(type, Abstract::Sub);
-      curr->left = right;
-      curr->right = left;
-      return curr;
-    }
-    // (unsigned)x <= -1   ==>   1
-    if (matches(curr, binary(Abstract::LeU, pure(&left), ival(-1)))) {
-      right->value = Literal::makeOne(Type::i32);
-      right->type = Type::i32;
-      return right;
-    }
-    {
-      // ~(1 << x) aka (1 << x) ^ -1  ==>  rotl(-2, x)
-      Expression* x;
-      if (matches(curr,
-                  binary(Abstract::Xor,
-                         binary(Abstract::Shl, ival(1), any(&x)),
-                         ival(-1)))) {
-        curr->op = Abstract::getBinary(type, Abstract::RotL);
-        right->value = Literal::makeFromInt32(-2, type);
-        curr->left = right;
-        curr->right = x;
-        return curr;
-      }
-    }
-    {
-      // Wasm binary encoding uses signed LEBs, which slightly favor negative
-      // numbers: -64 is more efficient than +64 etc., as well as other powers
-      // of two 7 bits etc. higher. we therefore prefer x - -64 over x + 64. in
-      // theory we could just prefer negative numbers over positive, but that
-      // can have bad effects on gzip compression (as it would mean more
-      // subtractions than the more common additions). TODO: Simplify this by
-      // adding an ival matcher than can bind int64_t vars.
-      int64_t value;
-      if ((matches(curr, binary(Abstract::Add, any(), ival(&value))) ||
-           matches(curr, binary(Abstract::Sub, any(), ival(&value)))) &&
-          (value == 0x40 || value == 0x2000 || value == 0x100000 ||
-           value == 0x8000000 || value == 0x400000000LL ||
-           value == 0x20000000000LL || value == 0x1000000000000LL ||
-           value == 0x80000000000000LL || value == 0x4000000000000000LL)) {
-        right->value = right->value.neg();
-        if (matches(curr, binary(Abstract::Add, any(), constant()))) {
-          curr->op = Abstract::getBinary(type, Abstract::Sub);
-        } else {
-          curr->op = Abstract::getBinary(type, Abstract::Add);
-        }
-        return curr;
-      }
-    }
-    {
-      double value;
-      if (matches(curr, binary(Abstract::Sub, any(), fval(&value))) &&
-          value == 0.0) {
-        // x - (-0.0)   ==>   x + 0.0
-        if (std::signbit(value)) {
-          curr->op = Abstract::getBinary(type, Abstract::Add);
-          right->value = right->value.neg();
-          return curr;
-        } else if (fastMath) {
-          // x - 0.0   ==>   x
-          return curr->left;
-        }
-      }
-    }
-    {
-      // x + (-0.0)   ==>   x
-      double value;
-      if (fastMath &&
-          matches(curr, binary(Abstract::Add, any(), fval(&value))) &&
-          value == 0.0 && std::signbit(value)) {
-        return curr->left;
-      }
-    }
-    // x * -1.0   ==>   -x
-    if (fastMath && matches(curr, binary(Abstract::Mul, any(), fval(-1.0)))) {
-      return builder.makeUnary(Abstract::getUnary(type, Abstract::Neg), left);
-    }
-    if (matches(curr, binary(Abstract::Mul, any(&left), constant(1))) ||
-        matches(curr, binary(Abstract::DivS, any(&left), constant(1))) ||
-        matches(curr, binary(Abstract::DivU, any(&left), constant(1)))) {
-      if (curr->type.isInteger() || fastMath) {
-        return left;
-      }
-    }
-    return nullptr;
-  }
-
-  // optimize trivial math operations, given that the left side of a binary
-  // is a constant. since we canonicalize constants to the right for symmetrical
-  // operations, we only need to handle asymmetrical ones here
-  // TODO: templatize on type?
-  Expression* optimizeWithConstantOnLeft(Binary* binary) {
-    auto type = binary->left->type;
-    auto* left = binary->left->cast<Const>();
-    if (type.isInteger()) {
-      // operations on zero
-      if (left->value == Literal::makeFromInt32(0, type)) {
-        if ((binary->op == Abstract::getBinary(type, Abstract::Shl) ||
-             binary->op == Abstract::getBinary(type, Abstract::ShrU) ||
-             binary->op == Abstract::getBinary(type, Abstract::ShrS)) &&
-            !effects(binary->right).hasSideEffects()) {
-          return binary->left;
-        }
-      }
-    }
-    return nullptr;
-  }
-
-  // TODO: templatize on type?
-  Expression* optimizeRelational(Binary* binary) {
-    // TODO: inequalities can also work, if the constants do not overflow
-    auto type = binary->right->type;
-    // integer math, even on 2s complement, allows stuff like
-    // x + 5 == 7
-    //   =>
-    //     x == 2
-    if (binary->left->type.isInteger()) {
-      if (binary->op == Abstract::getBinary(type, Abstract::Eq) ||
-          binary->op == Abstract::getBinary(type, Abstract::Ne)) {
-        if (auto* left = binary->left->dynCast<Binary>()) {
-          if (left->op == Abstract::getBinary(type, Abstract::Add) ||
-              left->op == Abstract::getBinary(type, Abstract::Sub)) {
-            if (auto* leftConst = left->right->dynCast<Const>()) {
-              if (auto* rightConst = binary->right->dynCast<Const>()) {
-                return combineRelationalConstants(
-                  binary, left, leftConst, nullptr, rightConst);
-              } else if (auto* rightBinary = binary->right->dynCast<Binary>()) {
-                if (rightBinary->op ==
-                      Abstract::getBinary(type, Abstract::Add) ||
-                    rightBinary->op ==
-                      Abstract::getBinary(type, Abstract::Sub)) {
-                  if (auto* rightConst = rightBinary->right->dynCast<Const>()) {
-                    return combineRelationalConstants(
-                      binary, left, leftConst, rightBinary, rightConst);
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-    return nullptr;
-  }
-
-  Expression* deduplicateUnary(Unary* unaryOuter) {
-    if (auto* unaryInner = unaryOuter->value->dynCast<Unary>()) {
-      if (unaryInner->op == unaryOuter->op) {
-        switch (unaryInner->op) {
-          case NegFloat32:
-          case NegFloat64: {
-            // neg(neg(x))  ==>   x
-            return unaryInner->value;
-          }
-          case AbsFloat32:
-          case CeilFloat32:
-          case FloorFloat32:
-          case TruncFloat32:
-          case NearestFloat32:
-          case AbsFloat64:
-          case CeilFloat64:
-          case FloorFloat64:
-          case TruncFloat64:
-          case NearestFloat64: {
-            // unaryOp(unaryOp(x))  ==>   unaryOp(x)
-            return unaryInner;
-          }
-          case ExtendS8Int32:
-          case ExtendS16Int32: {
-            assert(getModule()->features.hasSignExt());
-            return unaryInner;
-          }
-          case EqZInt32: {
-            // eqz(eqz(bool(x)))  ==>   bool(x)
-            if (Bits::getMaxBits(unaryInner->value, this) == 1) {
-              return unaryInner->value;
-            }
-            break;
-          }
-          default: {
-          }
-        }
-      }
-    }
-    return nullptr;
-  }
-
-  Expression* deduplicateBinary(Binary* outer) {
-    Type type = outer->type;
-    if (type.isInteger()) {
-      if (auto* inner = outer->right->dynCast<Binary>()) {
-        if (outer->op == inner->op) {
-          if (!EffectAnalyzer(
-                 getPassOptions(), getModule()->features, outer->left)
-                 .hasSideEffects()) {
-            if (ExpressionAnalyzer::equal(inner->left, outer->left)) {
-              // x - (x - y)  ==>   y
-              // x ^ (x ^ y)  ==>   y
-              if (outer->op == Abstract::getBinary(type, Abstract::Sub) ||
-                  outer->op == Abstract::getBinary(type, Abstract::Xor)) {
-                return inner->right;
-              }
-              // x & (x & y)  ==>   x & y
-              // x | (x | y)  ==>   x | y
-              if (outer->op == Abstract::getBinary(type, Abstract::And) ||
-                  outer->op == Abstract::getBinary(type, Abstract::Or)) {
-                return inner;
-              }
-            }
-            if (ExpressionAnalyzer::equal(inner->right, outer->left) &&
-                canReorder(outer->left, inner->left)) {
-              // x ^ (y ^ x)  ==>   y
-              // (note that we need the check for reordering here because if
-              // e.g. y writes to a local that x reads, the second appearance
-              // of x would be different from the first)
-              if (outer->op == Abstract::getBinary(type, Abstract::Xor)) {
-                return inner->left;
-              }
-
-              // x & (y & x)  ==>   y & x
-              // x | (y | x)  ==>   y | x
-              // (here we need the check for reordering for the more obvious
-              // reason that previously x appeared before y, and now y appears
-              // first; or, if we tried to emit x [&|] y here, reversing the
-              // order, we'd be in the same situation as the previous comment)
-              if (outer->op == Abstract::getBinary(type, Abstract::And) ||
-                  outer->op == Abstract::getBinary(type, Abstract::Or)) {
-                return inner;
-              }
-            }
-          }
-        }
-      }
-      if (auto* inner = outer->left->dynCast<Binary>()) {
-        if (outer->op == inner->op) {
-          if (!EffectAnalyzer(
-                 getPassOptions(), getModule()->features, outer->right)
-                 .hasSideEffects()) {
-            if (ExpressionAnalyzer::equal(inner->right, outer->right)) {
-              // (x ^ y) ^ y  ==>   x
-              if (outer->op == Abstract::getBinary(type, Abstract::Xor)) {
-                return inner->left;
-              }
-              // (x % y) % y  ==>   x % y
-              // (x & y) & y  ==>   x & y
-              // (x | y) | y  ==>   x | y
-              if (outer->op == Abstract::getBinary(type, Abstract::RemS) ||
-                  outer->op == Abstract::getBinary(type, Abstract::RemU) ||
-                  outer->op == Abstract::getBinary(type, Abstract::And) ||
-                  outer->op == Abstract::getBinary(type, Abstract::Or)) {
-                return inner;
-              }
-            }
-            // See comments in the parallel code earlier about ordering here.
-            if (ExpressionAnalyzer::equal(inner->left, outer->right) &&
-                canReorder(inner->left, inner->right)) {
-              // (x ^ y) ^ x  ==>   y
-              if (outer->op == Abstract::getBinary(type, Abstract::Xor)) {
-                return inner->right;
-              }
-              // (x & y) & x  ==>   x & y
-              // (x | y) | x  ==>   x | y
-              if (outer->op == Abstract::getBinary(type, Abstract::And) ||
-                  outer->op == Abstract::getBinary(type, Abstract::Or)) {
-                return inner;
-              }
-            }
-          }
-        }
-      }
-    }
-    return nullptr;
-  }
-
-  // given a relational binary with a const on both sides, combine the constants
-  // left is also a binary, and has a constant; right may be just a constant, in
-  // which case right is nullptr
-  Expression* combineRelationalConstants(Binary* binary,
-                                         Binary* left,
-                                         Const* leftConst,
-                                         Binary* right,
-                                         Const* rightConst) {
-    auto type = binary->right->type;
-    // we fold constants to the right
-    Literal extra = leftConst->value;
-    if (left->op == Abstract::getBinary(type, Abstract::Sub)) {
-      extra = extra.neg();
-    }
-    if (right && right->op == Abstract::getBinary(type, Abstract::Sub)) {
-      extra = extra.neg();
-    }
-    rightConst->value = rightConst->value.sub(extra);
-    binary->left = left->left;
-    return binary;
-  }
-
-  Expression* optimizeMemoryCopy(MemoryCopy* memCopy) {
-    PassOptions options = getPassOptions();
-
-    if (options.ignoreImplicitTraps) {
-      if (ExpressionAnalyzer::equal(memCopy->dest, memCopy->source)) {
-        // memory.copy(x, x, sz)  ==>  {drop(x), drop(x), drop(sz)}
-        Builder builder(*getModule());
-        return builder.makeBlock({builder.makeDrop(memCopy->dest),
-                                  builder.makeDrop(memCopy->source),
-                                  builder.makeDrop(memCopy->size)});
-      }
-    }
-
-    // memory.copy(dst, src, C)  ==>  store(dst, load(src))
-    if (auto* csize = memCopy->size->dynCast<Const>()) {
-      auto bytes = csize->value.geti32();
-      Builder builder(*getModule());
-
-      switch (bytes) {
-        case 0: {
-          if (options.ignoreImplicitTraps) {
-            // memory.copy(dst, src, 0)  ==>  {drop(dst), drop(src)}
-            return builder.makeBlock({builder.makeDrop(memCopy->dest),
-                                      builder.makeDrop(memCopy->source)});
-          }
-          break;
-        }
-        case 1:
-        case 2:
-        case 4: {
-          return builder.makeStore(
-            bytes, // bytes
-            0,     // offset
-            1,     // align
-            memCopy->dest,
-            builder.makeLoad(bytes, false, 0, 1, memCopy->source, Type::i32),
-            Type::i32);
-        }
-        case 8: {
-          return builder.makeStore(
-            bytes, // bytes
-            0,     // offset
-            1,     // align
-            memCopy->dest,
-            builder.makeLoad(bytes, false, 0, 1, memCopy->source, Type::i64),
-            Type::i64);
-        }
-        case 16: {
-          if (options.shrinkLevel == 0) {
-            // This adds an extra 2 bytes so apply it only for
-            // minimal shrink level
-            if (getModule()->features.hasSIMD()) {
-              return builder.makeStore(
-                bytes, // bytes
-                0,     // offset
-                1,     // align
-                memCopy->dest,
-                builder.makeLoad(
-                  bytes, false, 0, 1, memCopy->source, Type::v128),
-                Type::v128);
-            }
-          }
-        }
-        default: {
-        }
-      }
-    }
-    return nullptr;
-  }
-
-  // given a binary expression with equal children and no side effects in
-  // either, we can fold various things
-  Expression* optimizeBinaryWithEqualEffectlessChildren(Binary* binary) {
-    // TODO add: perhaps worth doing 2*x if x is quite large?
-    switch (binary->op) {
-      case SubInt32:
-      case XorInt32:
-      case SubInt64:
-      case XorInt64:
-        return LiteralUtils::makeZero(binary->left->type, *getModule());
-      case NeInt32:
-      case LtSInt32:
-      case LtUInt32:
-      case GtSInt32:
-      case GtUInt32:
-      case NeInt64:
-      case LtSInt64:
-      case LtUInt64:
-      case GtSInt64:
-      case GtUInt64:
-        return LiteralUtils::makeZero(Type::i32, *getModule());
-      case AndInt32:
-      case OrInt32:
-      case AndInt64:
-      case OrInt64:
-        return binary->left;
-      case EqInt32:
-      case LeSInt32:
-      case LeUInt32:
-      case GeSInt32:
-      case GeUInt32:
-      case EqInt64:
-      case LeSInt64:
-      case LeUInt64:
-      case GeSInt64:
-      case GeUInt64:
-        return LiteralUtils::makeFromInt32(1, Type::i32, *getModule());
-      default:
-        return nullptr;
-    }
-  }
-
-  BinaryOp invertBinaryOp(BinaryOp op) {
-    // use de-morgan's laws
-    switch (op) {
-      case EqInt32:
-        return NeInt32;
-      case NeInt32:
-        return EqInt32;
-      case LtSInt32:
-        return GeSInt32;
-      case LtUInt32:
-        return GeUInt32;
-      case LeSInt32:
-        return GtSInt32;
-      case LeUInt32:
-        return GtUInt32;
-      case GtSInt32:
-        return LeSInt32;
-      case GtUInt32:
-        return LeUInt32;
-      case GeSInt32:
-        return LtSInt32;
-      case GeUInt32:
-        return LtUInt32;
-
-      case EqInt64:
-        return NeInt64;
-      case NeInt64:
-        return EqInt64;
-      case LtSInt64:
-        return GeSInt64;
-      case LtUInt64:
-        return GeUInt64;
-      case LeSInt64:
-        return GtSInt64;
-      case LeUInt64:
-        return GtUInt64;
-      case GtSInt64:
-        return LeSInt64;
-      case GtUInt64:
-        return LeUInt64;
-      case GeSInt64:
-        return LtSInt64;
-      case GeUInt64:
-        return LtUInt64;
-
-      case EqFloat32:
-        return NeFloat32;
-      case NeFloat32:
-        return EqFloat32;
-
-      case EqFloat64:
-        return NeFloat64;
-      case NeFloat64:
-        return EqFloat64;
-
-      default:
-        return InvalidBinary;
-    }
-  }
-
-  BinaryOp makeUnsignedBinaryOp(BinaryOp op) {
-    switch (op) {
-      case DivSInt32:
-        return DivUInt32;
-      case RemSInt32:
-        return RemUInt32;
-      case ShrSInt32:
-        return ShrUInt32;
-      case LtSInt32:
-        return LtUInt32;
-      case LeSInt32:
-        return LeUInt32;
-      case GtSInt32:
-        return GtUInt32;
-      case GeSInt32:
-        return GeUInt32;
-
-      case DivSInt64:
-        return DivUInt64;
-      case RemSInt64:
-        return RemUInt64;
-      case ShrSInt64:
-        return ShrUInt64;
-      case LtSInt64:
-        return LtUInt64;
-      case LeSInt64:
-        return LeUInt64;
-      case GtSInt64:
-        return GtUInt64;
-      case GeSInt64:
-        return GeUInt64;
-
-      default:
-        return InvalidBinary;
-    }
-  }
-
-  bool isSymmetric(Binary* binary) {
-    if (Properties::isSymmetric(binary)) {
-      return true;
-    }
-    switch (binary->op) {
-      case AddFloat32:
-      case MulFloat32:
-      case AddFloat64:
-      case MulFloat64: {
-        // If the LHS is known to be non-NaN, the operands can commute.
-        // We don't care about the RHS because right now we only know if
-        // an expression is non-NaN if it is constant, but if the RHS is
-        // constant, then this expression is already canonicalized.
-        if (auto* c = binary->left->dynCast<Const>()) {
-          return !c->value.isNaN();
-        }
-        return false;
-      }
-      default:
-        return false;
-    }
-  }
-};
-
-Pass* createOptimizeInstructionsPass() { return new OptimizeInstructions(); }
+#include <cmath>
+#include <type_traits>
+
+#include <ir/abstract.h>
+#include <ir/bits.h>
+#include <ir/cost.h>
+#include <ir/effects.h>
+#include <ir/literal-utils.h>
+#include <ir/load-utils.h>
+#include <ir/manipulation.h>
+#include <ir/match.h>
+#include <ir/properties.h>
+#include <ir/utils.h>
+#include <pass.h>
+#include <support/threads.h>
+#include <wasm.h>
+
+// TODO: Use the new sign-extension opcodes where appropriate. This needs to be
+// conditionalized on the availability of atomics.
+
+namespace wasm {
+
+Name I32_EXPR = "i32.expr";
+Name I64_EXPR = "i64.expr";
+Name F32_EXPR = "f32.expr";
+Name F64_EXPR = "f64.expr";
+Name ANY_EXPR = "any.expr";
+
+// Useful information about locals
+struct LocalInfo {
+  static const Index kUnknown = Index(-1);
+
+  Index maxBits;
+  Index signExtedBits;
+};
+
+struct LocalScanner : PostWalker<LocalScanner> {
+  std::vector<LocalInfo>& localInfo;
+  const PassOptions& passOptions;
+
+  LocalScanner(std::vector<LocalInfo>& localInfo,
+               const PassOptions& passOptions)
+    : localInfo(localInfo), passOptions(passOptions) {}
+
+  void doWalkFunction(Function* func) {
+    // prepare
+    localInfo.resize(func->getNumLocals());
+    for (Index i = 0; i < func->getNumLocals(); i++) {
+      auto& info = localInfo[i];
+      if (func->isParam(i)) {
+        info.maxBits = getBitsForType(func->getLocalType(i)); // worst-case
+        info.signExtedBits = LocalInfo::kUnknown; // we will never know anything
+      } else {
+        info.maxBits = info.signExtedBits = 0; // we are open to learning
+      }
+    }
+    // walk
+    PostWalker<LocalScanner>::doWalkFunction(func);
+    // finalize
+    for (Index i = 0; i < func->getNumLocals(); i++) {
+      auto& info = localInfo[i];
+      if (info.signExtedBits == LocalInfo::kUnknown) {
+        info.signExtedBits = 0;
+      }
+    }
+  }
+
+  void visitLocalSet(LocalSet* curr) {
+    auto* func = getFunction();
+    if (func->isParam(curr->index)) {
+      return;
+    }
+    auto type = getFunction()->getLocalType(curr->index);
+    if (type != Type::i32 && type != Type::i64) {
+      return;
+    }
+    // an integer var, worth processing
+    auto* value = Properties::getFallthrough(
+      curr->value, passOptions, getModule()->features);
+    auto& info = localInfo[curr->index];
+    info.maxBits = std::max(info.maxBits, Bits::getMaxBits(value, this));
+    auto signExtBits = LocalInfo::kUnknown;
+    if (Properties::getSignExtValue(value)) {
+      signExtBits = Properties::getSignExtBits(value);
+    } else if (auto* load = value->dynCast<Load>()) {
+      if (LoadUtils::isSignRelevant(load) && load->signed_) {
+        signExtBits = load->bytes * 8;
+      }
+    }
+    if (info.signExtedBits == 0) {
+      info.signExtedBits = signExtBits; // first info we see
+    } else if (info.signExtedBits != signExtBits) {
+      // contradictory information, give up
+      info.signExtedBits = LocalInfo::kUnknown;
+    }
+  }
+
+  // define this for the templated getMaxBits method. we know nothing here yet
+  // about locals, so return the maxes
+  Index getMaxBitsForLocal(LocalGet* get) { return getBitsForType(get->type); }
+
+  Index getBitsForType(Type type) {
+    if (!type.isBasic()) {
+      return -1;
+    }
+    switch (type.getBasic()) {
+      case Type::i32:
+        return 32;
+      case Type::i64:
+        return 64;
+      default:
+        return -1;
+    }
+  }
+};
+
+namespace {
+// perform some final optimizations
+struct FinalOptimizer : public PostWalker<FinalOptimizer> {
+  const PassOptions& passOptions;
+
+  FinalOptimizer(const PassOptions& passOptions) : passOptions(passOptions) {}
+
+  void visitBinary(Binary* curr) {
+    if (auto* replacement = optimize(curr)) {
+      replaceCurrent(replacement);
+    }
+  }
+
+  Binary* optimize(Binary* curr) {
+    using namespace Abstract;
+    using namespace Match;
+    {
+      Const* c;
+      if (matches(curr, binary(Add, any(), ival(&c)))) {
+        // normalize x + (-C)  ==>   x - C
+        if (c->value.isNegative()) {
+          c->value = c->value.neg();
+          curr->op = Abstract::getBinary(c->type, Sub);
+        }
+        // Wasm binary encoding uses signed LEBs, which slightly favor negative
+        // numbers: -64 is more efficient than +64 etc., as well as other powers
+        // of two 7 bits etc. higher. we therefore prefer x - -64 over x + 64.
+        // in theory we could just prefer negative numbers over positive, but
+        // that can have bad effects on gzip compression (as it would mean more
+        // subtractions than the more common additions).
+        int64_t value = c->value.getInteger();
+        if (value == 0x40LL || value == 0x2000LL || value == 0x100000LL ||
+            value == 0x8000000LL || value == 0x400000000LL ||
+            value == 0x20000000000LL || value == 0x1000000000000LL ||
+            value == 0x80000000000000LL || value == 0x4000000000000000LL) {
+          c->value = c->value.neg();
+          if (curr->op == Abstract::getBinary(c->type, Add)) {
+            curr->op = Abstract::getBinary(c->type, Sub);
+          } else {
+            curr->op = Abstract::getBinary(c->type, Add);
+          }
+        }
+        return curr;
+      }
+    }
+    return nullptr;
+  }
+};
+
+} // anonymous namespace
+
+// Create a custom matcher for checking side effects
+template<class Opt> struct PureMatcherKind {};
+template<class Opt>
+struct Match::Internal::KindTypeRegistry<PureMatcherKind<Opt>> {
+  using matched_t = Expression*;
+  using data_t = Opt*;
+};
+template<class Opt> struct Match::Internal::MatchSelf<PureMatcherKind<Opt>> {
+  bool operator()(Expression* curr, Opt* opt) {
+    return !opt->effects(curr).hasSideEffects();
+  }
+};
+
+// Main pass class
+struct OptimizeInstructions
+  : public WalkerPass<
+      PostWalker<OptimizeInstructions,
+                 UnifiedExpressionVisitor<OptimizeInstructions>>> {
+  bool isFunctionParallel() override { return true; }
+
+  Pass* create() override { return new OptimizeInstructions; }
+
+  bool fastMath;
+
+  void doWalkFunction(Function* func) {
+    fastMath = getPassOptions().fastMath;
+    // first, scan locals
+    {
+      LocalScanner scanner(localInfo, getPassOptions());
+      scanner.setModule(getModule());
+      scanner.walkFunction(func);
+    }
+    // main walk
+    super::doWalkFunction(func);
+    {
+      FinalOptimizer optimizer(getPassOptions());
+      optimizer.walkFunction(func);
+    }
+  }
+
+  void visitExpression(Expression* curr) {
+    // if this contains dead code, don't bother trying to optimize it, the type
+    // might change (if might not be unreachable if just one arm is, for
+    // example). this optimization pass focuses on actually executing code. the
+    // only exceptions are control flow changes
+    if (curr->is<Const>() || curr->is<Call>() || curr->is<Nop>() ||
+        (curr->type == Type::unreachable && !curr->is<Break>() &&
+         !curr->is<Switch>() && !curr->is<If>())) {
+      return;
+    }
+    // we may be able to apply multiple patterns, one may open opportunities
+    // that look deeper NB: patterns must not have cycles
+    while ((curr = handOptimize(curr))) {
+      replaceCurrent(curr);
+    }
+  }
+
+  EffectAnalyzer effects(Expression* expr) {
+    return EffectAnalyzer(getPassOptions(), getModule()->features, expr);
+  }
+
+  decltype(auto) pure(Expression** binder) {
+    using namespace Match::Internal;
+    return Matcher<PureMatcherKind<OptimizeInstructions>>(binder, this);
+  }
+
+  bool canReorder(Expression* a, Expression* b) {
+    return EffectAnalyzer::canReorder(
+      getPassOptions(), getModule()->features, a, b);
+  }
+
+  // Optimizations that don't yet fit in the pattern DSL, but could be
+  // eventually maybe
+  Expression* handOptimize(Expression* curr) {
+    if (curr->is<Const>()) {
+      return nullptr;
+    }
+
+    FeatureSet features = getModule()->features;
+
+    if (auto* binary = curr->dynCast<Binary>()) {
+      if (shouldCanonicalize(binary)) {
+        canonicalize(binary);
+      }
+    }
+
+    {
+      // TODO: It is an ongoing project to port more transformations to the
+      // match API. Once most of the transformations have been ported, the
+      // `using namespace Match` can be hoisted to function scope and this extra
+      // block scope can be removed.
+      using namespace Match;
+      using namespace Abstract;
+      Builder builder(*getModule());
+      {
+        // try to get rid of (0 - ..), that is, a zero only used to negate an
+        // int. an add of a subtract can be flipped in order to remove it:
+        //   (ival.add
+        //     (ival.sub
+        //       (ival.const 0)
+        //       X
+        //     )
+        //     Y
+        //   )
+        // =>
+        //   (ival.sub
+        //     Y
+        //     X
+        //   )
+        // Note that this reorders X and Y, so we need to be careful about that.
+        Expression *x, *y;
+        Binary* sub;
+        if (matches(
+              curr,
+              binary(Add, binary(&sub, Sub, ival(0), any(&x)), any(&y))) &&
+            canReorder(x, y)) {
+          sub->left = y;
+          sub->right = x;
+          return sub;
+        }
+      }
+      {
+        // The flip case is even easier, as no reordering occurs:
+        //   (ival.add
+        //     Y
+        //     (ival.sub
+        //       (ival.const 0)
+        //       X
+        //     )
+        //   )
+        // =>
+        //   (ival.sub
+        //     Y
+        //     X
+        //   )
+        Expression* y;
+        Binary* sub;
+        if (matches(curr,
+                    binary(Add, any(&y), binary(&sub, Sub, ival(0), any())))) {
+          sub->left = y;
+          return sub;
+        }
+      }
+      {
+        // eqz(x - y)  =>  x == y
+        Binary* inner;
+        if (matches(curr, unary(EqZ, binary(&inner, Sub, any(), any())))) {
+          inner->op = Abstract::getBinary(inner->left->type, Eq);
+          inner->type = Type::i32;
+          return inner;
+        }
+      }
+      {
+        // eqz(x + C)  =>  x == -C
+        Const* c;
+        Binary* inner;
+        if (matches(curr, unary(EqZ, binary(&inner, Add, any(), ival(&c))))) {
+          c->value = c->value.neg();
+          inner->op = Abstract::getBinary(c->type, Eq);
+          inner->type = Type::i32;
+          return inner;
+        }
+      }
+      {
+        // eqz((signed)x % C_pot)  =>  eqz(x & (abs(C_pot) - 1))
+        Const* c;
+        Binary* inner;
+        if (matches(curr, unary(EqZ, binary(&inner, RemS, any(), ival(&c)))) &&
+            (c->value.isSignedMin() ||
+             Bits::isPowerOf2(c->value.abs().getInteger()))) {
+          inner->op = Abstract::getBinary(c->type, And);
+          if (c->value.isSignedMin()) {
+            c->value = Literal::makeSignedMax(c->type);
+          } else {
+            c->value = c->value.abs().sub(Literal::makeOne(c->type));
+          }
+          return curr;
+        }
+      }
+      {
+        // try de-morgan's AND law,
+        //  (eqz X) and (eqz Y) === eqz (X or Y)
+        // Note that the OR and XOR laws do not work here, as these
+        // are not booleans (we could check if they are, but a boolean
+        // would already optimize with the eqz anyhow, unless propagating).
+        // But for AND, the left is true iff X and Y are each all zero bits,
+        // and the right is true if the union of their bits is zero; same.
+        Unary* un;
+        Binary* bin;
+        Expression *x, *y;
+        if (matches(curr,
+                    binary(&bin,
+                           AndInt32,
+                           unary(&un, EqZInt32, any(&x)),
+                           unary(EqZInt32, any(&y))))) {
+          bin->op = OrInt32;
+          bin->left = x;
+          bin->right = y;
+          un->value = bin;
+          return un;
+        }
+      }
+      {
+        // i32.eqz(i32.wrap_i64(x))  =>  i64.eqz(x)
+        //   where maxBits(x) <= 32
+        Unary* inner;
+        Expression* x;
+        if (matches(curr, unary(EqZInt32, unary(&inner, WrapInt64, any(&x)))) &&
+            Bits::getMaxBits(x, this) <= 32) {
+          inner->op = EqZInt64;
+          inner->value = x;
+          return inner;
+        }
+      }
+      {
+        // x <<>> (C & (31 | 63))   ==>   x <<>> C'
+        // x <<>> (y & (31 | 63))   ==>   x <<>> y
+        // x <<>> (y & (32 | 64))   ==>   x
+        // where '<<>>':
+        //   '<<', '>>', '>>>'. 'rotl' or 'rotr'
+        BinaryOp op;
+        Const* c;
+        Expression *x, *y;
+
+        // x <<>> C
+        if (matches(curr, binary(&op, any(&x), ival(&c))) &&
+            Abstract::hasAnyShift(op)) {
+          // truncate RHS constant to effective size as:
+          // i32(x) <<>> const(C & 31))
+          // i64(x) <<>> const(C & 63))
+          c->value = c->value.and_(
+            Literal::makeFromInt32(c->type.getByteSize() * 8 - 1, c->type));
+          // x <<>> 0   ==>   x
+          if (c->value.isZero()) {
+            return x;
+          }
+        }
+        if (matches(curr,
+                    binary(&op, any(&x), binary(And, any(&y), ival(&c)))) &&
+            Abstract::hasAnyShift(op)) {
+          // i32(x) <<>> (y & 31)   ==>   x <<>> y
+          // i64(x) <<>> (y & 63)   ==>   x <<>> y
+          if ((c->type == Type::i32 && (c->value.geti32() & 31) == 31) ||
+              (c->type == Type::i64 && (c->value.geti64() & 63LL) == 63LL)) {
+            curr->cast<Binary>()->right = y;
+            return curr;
+          }
+          // i32(x) <<>> (y & C)   ==>   x,  where (C & 31) == 0
+          // i64(x) <<>> (y & C)   ==>   x,  where (C & 63) == 0
+          if (((c->type == Type::i32 && (c->value.geti32() & 31) == 0) ||
+               (c->type == Type::i64 && (c->value.geti64() & 63LL) == 0LL)) &&
+              !effects(y).hasSideEffects()) {
+            return x;
+          }
+        }
+      }
+      {
+        // unsigned(x) >= 0   =>   i32(1)
+        Const* c;
+        Expression* x;
+        if (matches(curr, binary(GeU, pure(&x), ival(&c))) &&
+            c->value.isZero()) {
+          c->value = Literal::makeOne(Type::i32);
+          c->type = Type::i32;
+          return c;
+        }
+        // unsigned(x) < 0   =>   i32(0)
+        if (matches(curr, binary(LtU, pure(&x), ival(&c))) &&
+            c->value.isZero()) {
+          c->value = Literal::makeZero(Type::i32);
+          c->type = Type::i32;
+          return c;
+        }
+      }
+    }
+
+    if (auto* select = curr->dynCast<Select>()) {
+      return optimizeSelect(select);
+    }
+
+    if (auto* binary = curr->dynCast<Binary>()) {
+      if (auto* ext = Properties::getAlmostSignExt(binary)) {
+        Index extraLeftShifts;
+        auto bits = Properties::getAlmostSignExtBits(binary, extraLeftShifts);
+        if (extraLeftShifts == 0) {
+          if (auto* load =
+                Properties::getFallthrough(ext, getPassOptions(), features)
+                  ->dynCast<Load>()) {
+            // pattern match a load of 8 bits and a sign extend using a shl of
+            // 24 then shr_s of 24 as well, etc.
+            if (LoadUtils::canBeSigned(load) &&
+                ((load->bytes == 1 && bits == 8) ||
+                 (load->bytes == 2 && bits == 16))) {
+              // if the value falls through, we can't alter the load, as it
+              // might be captured in a tee
+              if (load->signed_ == true || load == ext) {
+                load->signed_ = true;
+                return ext;
+              }
+            }
+          }
+        }
+        // We can in some cases remove part of a sign extend, that is,
+        //   (x << A) >> B   =>   x << (A - B)
+        // If the sign-extend input cannot have a sign bit, we don't need it.
+        if (Bits::getMaxBits(ext, this) + extraLeftShifts < bits) {
+          return removeAlmostSignExt(binary);
+        }
+        // We also don't need it if it already has an identical-sized sign
+        // extend applied to it. That is, if it is already a sign-extended
+        // value, then another sign extend will do nothing. We do need to be
+        // careful of the extra shifts, though.
+        if (isSignExted(ext, bits) && extraLeftShifts == 0) {
+          return removeAlmostSignExt(binary);
+        }
+      } else if (binary->op == EqInt32 || binary->op == NeInt32) {
+        if (auto* c = binary->right->dynCast<Const>()) {
+          if (auto* ext = Properties::getSignExtValue(binary->left)) {
+            // We are comparing a sign extend to a constant, which means we can
+            // use a cheaper zero-extend in some cases. That is,
+            //  (x << S) >> S ==/!= C    =>    x & T ==/!= C
+            // where S and T are the matching values for sign/zero extend of the
+            // same size. For example, for an effective 8-bit value:
+            //  (x << 24) >> 24 ==/!= C    =>    x & 255 ==/!= C
+            //
+            // The key thing to track here are the upper bits plus the sign bit;
+            // call those the "relevant bits". This is crucial because x is
+            // sign-extended, that is, its effective sign bit is spread to all
+            // the upper bits, which means that the relevant bits on the left
+            // side are either all 0, or all 1.
+            auto bits = Properties::getSignExtBits(binary->left);
+            uint32_t right = c->value.geti32();
+            uint32_t numRelevantBits = 32 - bits + 1;
+            uint32_t setRelevantBits =
+              Bits::popCount(right >> uint32_t(bits - 1));
+            // If all the relevant bits on C are zero
+            // then we can mask off the high bits instead of sign-extending x.
+            // This is valid because if x is negative, then the comparison was
+            // false before (negative vs positive), and will still be false
+            // as the sign bit will remain to cause a difference. And if x is
+            // positive then the upper bits would be zero anyhow.
+            if (setRelevantBits == 0) {
+              binary->left = makeZeroExt(ext, bits);
+              return binary;
+            } else if (setRelevantBits == numRelevantBits) {
+              // If all those bits are one, then we can do something similar if
+              // we also zero-extend on the right as well. This is valid
+              // because, as in the previous case, the sign bit differentiates
+              // the two sides when they are different, and if the sign bit is
+              // identical, then the upper bits don't matter, so masking them
+              // off both sides is fine.
+              binary->left = makeZeroExt(ext, bits);
+              c->value = c->value.and_(Literal(Bits::lowBitMask(bits)));
+              return binary;
+            } else {
+              // Otherwise, C's relevant bits are mixed, and then the two sides
+              // can never be equal, as the left side's bits cannot be mixed.
+              Builder builder(*getModule());
+              // The result is either always true, or always false.
+              c->value = Literal::makeFromInt32(binary->op == NeInt32, c->type);
+              return builder.makeSequence(builder.makeDrop(ext), c);
+            }
+          }
+        } else if (auto* left = Properties::getSignExtValue(binary->left)) {
+          if (auto* right = Properties::getSignExtValue(binary->right)) {
+            auto bits = Properties::getSignExtBits(binary->left);
+            if (Properties::getSignExtBits(binary->right) == bits) {
+              // we are comparing two sign-exts with the same bits, so we may as
+              // well replace both with cheaper zexts
+              binary->left = makeZeroExt(left, bits);
+              binary->right = makeZeroExt(right, bits);
+              return binary;
+            }
+          } else if (auto* load = binary->right->dynCast<Load>()) {
+            // we are comparing a load to a sign-ext, we may be able to switch
+            // to zext
+            auto leftBits = Properties::getSignExtBits(binary->left);
+            if (load->signed_ && leftBits == load->bytes * 8) {
+              load->signed_ = false;
+              binary->left = makeZeroExt(left, leftBits);
+              return binary;
+            }
+          }
+        } else if (auto* load = binary->left->dynCast<Load>()) {
+          if (auto* right = Properties::getSignExtValue(binary->right)) {
+            // we are comparing a load to a sign-ext, we may be able to switch
+            // to zext
+            auto rightBits = Properties::getSignExtBits(binary->right);
+            if (load->signed_ && rightBits == load->bytes * 8) {
+              load->signed_ = false;
+              binary->right = makeZeroExt(right, rightBits);
+              return binary;
+            }
+          }
+        }
+        // note that both left and right may be consts, but then we let
+        // precompute compute the constant result
+      } else if (binary->op == AddInt32 || binary->op == AddInt64 ||
+                 binary->op == SubInt32 || binary->op == SubInt64) {
+        if (auto* ret = optimizeAddedConstants(binary)) {
+          return ret;
+        }
+      } else if (binary->op == MulFloat32 || binary->op == MulFloat64 ||
+                 binary->op == DivFloat32 || binary->op == DivFloat64) {
+        if (binary->left->type == binary->right->type) {
+          if (auto* leftUnary = binary->left->dynCast<Unary>()) {
+            if (leftUnary->op ==
+                Abstract::getUnary(binary->type, Abstract::Abs)) {
+              if (auto* rightUnary = binary->right->dynCast<Unary>()) {
+                if (leftUnary->op == rightUnary->op) { // both are abs ops
+                  // abs(x) * abs(y)   ==>   abs(x * y)
+                  // abs(x) / abs(y)   ==>   abs(x / y)
+                  binary->left = leftUnary->value;
+                  binary->right = rightUnary->value;
+                  leftUnary->value = binary;
+                  return leftUnary;
+                }
+              }
+            }
+          }
+        }
+      }
+      // a bunch of operations on a constant right side can be simplified
+      if (auto* right = binary->right->dynCast<Const>()) {
+        if (binary->op == AndInt32) {
+          auto mask = right->value.geti32();
+          // and with -1 does nothing (common in asm.js output)
+          if (mask == -1) {
+            return binary->left;
+          }
+          // small loads do not need to be masked, the load itself masks
+          if (auto* load = binary->left->dynCast<Load>()) {
+            if ((load->bytes == 1 && mask == 0xff) ||
+                (load->bytes == 2 && mask == 0xffff)) {
+              load->signed_ = false;
+              return binary->left;
+            }
+          } else if (auto maskedBits = Bits::getMaskedBits(mask)) {
+            if (Bits::getMaxBits(binary->left, this) <= maskedBits) {
+              // a mask of lower bits is not needed if we are already smaller
+              return binary->left;
+            }
+          }
+        }
+        // some math operations have trivial results
+        if (auto* ret = optimizeWithConstantOnRight(binary)) {
+          return ret;
+        }
+        // the square of some operations can be merged
+        if (auto* left = binary->left->dynCast<Binary>()) {
+          if (left->op == binary->op) {
+            if (auto* leftRight = left->right->dynCast<Const>()) {
+              if (left->op == AndInt32 || left->op == AndInt64) {
+                leftRight->value = leftRight->value.and_(right->value);
+                return left;
+              } else if (left->op == OrInt32 || left->op == OrInt64) {
+                leftRight->value = leftRight->value.or_(right->value);
+                return left;
+              } else if (left->op == XorInt32 || left->op == XorInt64) {
+                leftRight->value = leftRight->value.xor_(right->value);
+                return left;
+              } else if (left->op == MulInt32 || left->op == MulInt64) {
+                leftRight->value = leftRight->value.mul(right->value);
+                return left;
+
+                // TODO:
+                // handle signed / unsigned divisions. They are more complex
+              } else if (left->op == ShlInt32 || left->op == ShrUInt32 ||
+                         left->op == ShrSInt32 || left->op == ShlInt64 ||
+                         left->op == ShrUInt64 || left->op == ShrSInt64) {
+                // shifts only use an effective amount from the constant, so
+                // adding must be done carefully
+                auto total = Bits::getEffectiveShifts(leftRight) +
+                             Bits::getEffectiveShifts(right);
+                if (total == Bits::getEffectiveShifts(total, right->type)) {
+                  // no overflow, we can do this
+                  leftRight->value = Literal::makeFromInt32(total, right->type);
+                  return left;
+                } // TODO: handle overflows
+              }
+            }
+          }
+        }
+        if (right->type == Type::i32) {
+          BinaryOp op;
+          int32_t c = right->value.geti32();
+          // First, try to lower signed operations to unsigned if that is
+          // possible. Some unsigned operations like div_u or rem_u are usually
+          // faster on VMs. Also this opens more possibilities for further
+          // simplifications afterwards.
+          if (c >= 0 &&
+              (op = makeUnsignedBinaryOp(binary->op)) != InvalidBinary &&
+              Bits::getMaxBits(binary->left, this) <= 31) {
+            binary->op = op;
+          }
+          if (c < 0 && c > std::numeric_limits<int32_t>::min() &&
+              binary->op == DivUInt32) {
+            // u32(x) / C   ==>   u32(x) >= C  iff C > 2^31
+            // We avoid applying this for C == 2^31 due to conflict
+            // with other rule which transform to more prefereble
+            // right shift operation.
+            binary->op = c == -1 ? EqInt32 : GeUInt32;
+            return binary;
+          }
+          if (Bits::isPowerOf2((uint32_t)c)) {
+            switch (binary->op) {
+              case MulInt32:
+                return optimizePowerOf2Mul(binary, (uint32_t)c);
+              case RemUInt32:
+                return optimizePowerOf2URem(binary, (uint32_t)c);
+              case DivUInt32:
+                return optimizePowerOf2UDiv(binary, (uint32_t)c);
+              default:
+                break;
+            }
+          }
+        }
+        if (right->type == Type::i64) {
+          BinaryOp op;
+          int64_t c = right->value.geti64();
+          // See description above for Type::i32
+          if (c >= 0 &&
+              (op = makeUnsignedBinaryOp(binary->op)) != InvalidBinary &&
+              Bits::getMaxBits(binary->left, this) <= 63) {
+            binary->op = op;
+          }
+          if (getPassOptions().shrinkLevel == 0 && c < 0 &&
+              c > std::numeric_limits<int64_t>::min() &&
+              binary->op == DivUInt64) {
+            // u64(x) / C   ==>   u64(u64(x) >= C)  iff C > 2^63
+            // We avoid applying this for C == 2^31 due to conflict
+            // with other rule which transform to more prefereble
+            // right shift operation.
+            // And apply this only for shrinkLevel == 0 due to it
+            // increasing size by one byte.
+            binary->op = c == -1LL ? EqInt64 : GeUInt64;
+            binary->type = Type::i32;
+            return Builder(*getModule()).makeUnary(ExtendUInt32, binary);
+          }
+          if (Bits::isPowerOf2((uint64_t)c)) {
+            switch (binary->op) {
+              case MulInt64:
+                return optimizePowerOf2Mul(binary, (uint64_t)c);
+              case RemUInt64:
+                return optimizePowerOf2URem(binary, (uint64_t)c);
+              case DivUInt64:
+                return optimizePowerOf2UDiv(binary, (uint64_t)c);
+              default:
+                break;
+            }
+          }
+        }
+        if (binary->op == DivFloat32) {
+          float c = right->value.getf32();
+          if (Bits::isPowerOf2InvertibleFloat(c)) {
+            return optimizePowerOf2FDiv(binary, c);
+          }
+        }
+        if (binary->op == DivFloat64) {
+          double c = right->value.getf64();
+          if (Bits::isPowerOf2InvertibleFloat(c)) {
+            return optimizePowerOf2FDiv(binary, c);
+          }
+        }
+      }
+      // a bunch of operations on a constant left side can be simplified
+      if (binary->left->is<Const>()) {
+        if (auto* ret = optimizeWithConstantOnLeft(binary)) {
+          return ret;
+        }
+      }
+      // bitwise operations
+      // for and and or, we can potentially conditionalize
+      if (binary->op == AndInt32 || binary->op == OrInt32) {
+        if (auto* ret = conditionalizeExpensiveOnBitwise(binary)) {
+          return ret;
+        }
+      }
+      // for or, we can potentially combine
+      if (binary->op == OrInt32) {
+        if (auto* ret = combineOr(binary)) {
+          return ret;
+        }
+      }
+      // relation/comparisons allow for math optimizations
+      if (binary->isRelational()) {
+        if (auto* ret = optimizeRelational(binary)) {
+          return ret;
+        }
+      }
+      // finally, try more expensive operations on the binary in
+      // the case that they have no side effects
+      if (!effects(binary->left).hasSideEffects()) {
+        if (ExpressionAnalyzer::equal(binary->left, binary->right)) {
+          if (auto* ret = optimizeBinaryWithEqualEffectlessChildren(binary)) {
+            return ret;
+          }
+        }
+      }
+
+      if (auto* ret = deduplicateBinary(binary)) {
+        return ret;
+      }
+    } else if (auto* unary = curr->dynCast<Unary>()) {
+      if (unary->op == EqZInt32) {
+        if (auto* inner = unary->value->dynCast<Binary>()) {
+          // Try to invert a relational operation using De Morgan's law
+          auto op = invertBinaryOp(inner->op);
+          if (op != InvalidBinary) {
+            inner->op = op;
+            return inner;
+          }
+        }
+        // eqz of a sign extension can be of zero-extension
+        if (auto* ext = Properties::getSignExtValue(unary->value)) {
+          // we are comparing a sign extend to a constant, which means we can
+          // use a cheaper zext
+          auto bits = Properties::getSignExtBits(unary->value);
+          unary->value = makeZeroExt(ext, bits);
+          return unary;
+        }
+      } else if (unary->op == AbsFloat32 || unary->op == AbsFloat64) {
+        // abs(-x)   ==>   abs(x)
+        if (auto* unaryInner = unary->value->dynCast<Unary>()) {
+          if (unaryInner->op ==
+              Abstract::getUnary(unaryInner->type, Abstract::Neg)) {
+            unary->value = unaryInner->value;
+            return unary;
+          }
+        }
+        // abs(x * x)   ==>   x * x
+        // abs(x / x)   ==>   x / x
+        if (auto* binary = unary->value->dynCast<Binary>()) {
+          if ((binary->op == Abstract::getBinary(binary->type, Abstract::Mul) ||
+               binary->op ==
+                 Abstract::getBinary(binary->type, Abstract::DivS)) &&
+              ExpressionAnalyzer::equal(binary->left, binary->right)) {
+            return binary;
+          }
+          // abs(0 - x)   ==>   abs(x),
+          // only for fast math
+          if (fastMath &&
+              binary->op == Abstract::getBinary(binary->type, Abstract::Sub)) {
+            if (auto* c = binary->left->dynCast<Const>()) {
+              if (c->value.isZero()) {
+                unary->value = binary->right;
+                return unary;
+              }
+            }
+          }
+        }
+      }
+
+      if (auto* ret = deduplicateUnary(unary)) {
+        return ret;
+      }
+    } else if (auto* set = curr->dynCast<GlobalSet>()) {
+      // optimize out a set of a get
+      auto* get = set->value->dynCast<GlobalGet>();
+      if (get && get->name == set->name) {
+        ExpressionManipulator::nop(curr);
+      }
+    } else if (auto* iff = curr->dynCast<If>()) {
+      iff->condition = optimizeBoolean(iff->condition);
+      if (iff->ifFalse) {
+        if (auto* unary = iff->condition->dynCast<Unary>()) {
+          if (unary->op == EqZInt32) {
+            // flip if-else arms to get rid of an eqz
+            iff->condition = unary->value;
+            std::swap(iff->ifTrue, iff->ifFalse);
+          }
+        }
+        if (iff->condition->type != Type::unreachable &&
+            ExpressionAnalyzer::equal(iff->ifTrue, iff->ifFalse)) {
+          // sides are identical, fold
+          // if we can replace the if with one arm, and no side effects in the
+          // condition, do that
+          auto needCondition = effects(iff->condition).hasSideEffects();
+          auto isSubType = Type::isSubType(iff->ifTrue->type, iff->type);
+          if (isSubType && !needCondition) {
+            return iff->ifTrue;
+          } else {
+            Builder builder(*getModule());
+            if (isSubType) {
+              return builder.makeSequence(builder.makeDrop(iff->condition),
+                                          iff->ifTrue);
+            } else {
+              // the types diff. as the condition is reachable, that means the
+              // if must be concrete while the arm is not
+              assert(iff->type.isConcrete() &&
+                     iff->ifTrue->type == Type::unreachable);
+              // emit a block with a forced type
+              auto* ret = builder.makeBlock();
+              if (needCondition) {
+                ret->list.push_back(builder.makeDrop(iff->condition));
+              }
+              ret->list.push_back(iff->ifTrue);
+              ret->finalize(iff->type);
+              return ret;
+            }
+          }
+        }
+      }
+    } else if (auto* br = curr->dynCast<Break>()) {
+      if (br->condition) {
+        br->condition = optimizeBoolean(br->condition);
+      }
+    } else if (auto* load = curr->dynCast<Load>()) {
+      optimizeMemoryAccess(load->ptr, load->offset);
+    } else if (auto* store = curr->dynCast<Store>()) {
+      optimizeMemoryAccess(store->ptr, store->offset);
+      if (store->valueType.isInteger()) {
+        // truncates constant values during stores
+        // (i32|i64).store(8|16|32)(p, C)   ==>
+        //    (i32|i64).store(8|16|32)(p, C & mask)
+        if (auto* c = store->value->dynCast<Const>()) {
+          if (store->valueType == Type::i64 && store->bytes == 4) {
+            c->value = c->value.and_(Literal(uint64_t(0xffffffff)));
+          } else {
+            c->value = c->value.and_(Literal::makeFromInt32(
+              Bits::lowBitMask(store->bytes * 8), store->valueType));
+          }
+        }
+      }
+      // stores of fewer bits truncates anyhow
+      if (auto* binary = store->value->dynCast<Binary>()) {
+        if (binary->op == AndInt32) {
+          if (auto* right = binary->right->dynCast<Const>()) {
+            if (right->type == Type::i32) {
+              auto mask = right->value.geti32();
+              if ((store->bytes == 1 && mask == 0xff) ||
+                  (store->bytes == 2 && mask == 0xffff)) {
+                store->value = binary->left;
+              }
+            }
+          }
+        } else if (auto* ext = Properties::getSignExtValue(binary)) {
+          // if sign extending the exact bit size we store, we can skip the
+          // extension if extending something bigger, then we just alter bits we
+          // don't save anyhow
+          if (Properties::getSignExtBits(binary) >= Index(store->bytes) * 8) {
+            store->value = ext;
+          }
+        }
+      } else if (auto* unary = store->value->dynCast<Unary>()) {
+        if (unary->op == WrapInt64) {
+          // instead of wrapping to 32, just store some of the bits in the i64
+          store->valueType = Type::i64;
+          store->value = unary->value;
+        }
+      }
+    } else if (auto* memCopy = curr->dynCast<MemoryCopy>()) {
+      assert(features.hasBulkMemory());
+      if (auto* ret = optimizeMemoryCopy(memCopy)) {
+        return ret;
+      }
+    }
+    return nullptr;
+  }
+
+  Index getMaxBitsForLocal(LocalGet* get) {
+    // check what we know about the local
+    return localInfo[get->index].maxBits;
+  }
+
+private:
+  // Information about our locals
+  std::vector<LocalInfo> localInfo;
+
+  // Canonicalizing the order of a symmetric binary helps us
+  // write more concise pattern matching code elsewhere.
+  void canonicalize(Binary* binary) {
+    assert(shouldCanonicalize(binary));
+    auto swap = [&]() {
+      assert(canReorder(binary->left, binary->right));
+      if (binary->isRelational()) {
+        binary->op = reverseRelationalOp(binary->op);
+      }
+      std::swap(binary->left, binary->right);
+    };
+    auto maybeSwap = [&]() {
+      if (canReorder(binary->left, binary->right)) {
+        swap();
+      }
+    };
+    // Prefer a const on the right.
+    if (binary->left->is<Const>() && !binary->right->is<Const>()) {
+      return swap();
+    }
+    if (auto* c = binary->right->dynCast<Const>()) {
+      // x - C  ==>   x + (-C)
+      // Prefer use addition if there is a constant on the right.
+      if (binary->op == Abstract::getBinary(c->type, Abstract::Sub)) {
+        c->value = c->value.neg();
+        binary->op = Abstract::getBinary(c->type, Abstract::Add);
+      }
+      return;
+    }
+    // Prefer a get on the right.
+    if (binary->left->is<LocalGet>() && !binary->right->is<LocalGet>()) {
+      return maybeSwap();
+    }
+    // Sort by the node id type, if different.
+    if (binary->left->_id != binary->right->_id) {
+      if (binary->left->_id > binary->right->_id) {
+        return maybeSwap();
+      }
+      return;
+    }
+    // If the children have the same node id, we have to go deeper.
+    if (auto* left = binary->left->dynCast<Unary>()) {
+      auto* right = binary->right->cast<Unary>();
+      if (left->op > right->op) {
+        return maybeSwap();
+      }
+    }
+    if (auto* left = binary->left->dynCast<Binary>()) {
+      auto* right = binary->right->cast<Binary>();
+      if (left->op > right->op) {
+        return maybeSwap();
+      }
+    }
+    if (auto* left = binary->left->dynCast<LocalGet>()) {
+      auto* right = binary->right->cast<LocalGet>();
+      if (left->index > right->index) {
+        return maybeSwap();
+      }
+    }
+  }
+
+  // Optimize given that the expression is flowing into a boolean context
+  Expression* optimizeBoolean(Expression* boolean) {
+    // TODO use a general getFallthroughs
+    if (auto* unary = boolean->dynCast<Unary>()) {
+      if (unary) {
+        if (unary->op == EqZInt32) {
+          auto* unary2 = unary->value->dynCast<Unary>();
+          if (unary2 && unary2->op == EqZInt32) {
+            // double eqz
+            return unary2->value;
+          }
+          if (auto* binary = unary->value->dynCast<Binary>()) {
+            // !(x <=> y)   ==>   x <!=> y
+            auto op = invertBinaryOp(binary->op);
+            if (op != InvalidBinary) {
+              binary->op = op;
+              return binary;
+            }
+          }
+        }
+      }
+    } else if (auto* binary = boolean->dynCast<Binary>()) {
+      if (binary->op == SubInt32) {
+        if (auto* c = binary->left->dynCast<Const>()) {
+          if (c->value.geti32() == 0) {
+            // bool(0 - x)   ==>   bool(x)
+            return binary->right;
+          }
+        }
+      } else if (binary->op == OrInt32) {
+        // an or flowing into a boolean context can consider each input as
+        // boolean
+        binary->left = optimizeBoolean(binary->left);
+        binary->right = optimizeBoolean(binary->right);
+      } else if (binary->op == NeInt32) {
+        if (auto* c = binary->right->dynCast<Const>()) {
+          // x != 0 is just x if it's used as a bool
+          if (c->value.geti32() == 0) {
+            return binary->left;
+          }
+          // TODO: Perhaps use it for separate final pass???
+          // x != -1   ==>    x ^ -1
+          // if (num->value.geti32() == -1) {
+          //   binary->op = XorInt32;
+          //   return binary;
+          // }
+        }
+      } else if (binary->op == RemSInt32) {
+        // bool(i32(x) % C_pot)  ==>  bool(x & (C_pot - 1))
+        // bool(i32(x) % min_s)  ==>  bool(x & max_s)
+        if (auto* c = binary->right->dynCast<Const>()) {
+          if (c->value.isSignedMin() ||
+              Bits::isPowerOf2(c->value.abs().geti32())) {
+            binary->op = AndInt32;
+            if (c->value.isSignedMin()) {
+              c->value = Literal::makeSignedMax(Type::i32);
+            } else {
+              c->value = c->value.abs().sub(Literal::makeOne(Type::i32));
+            }
+            return binary;
+          }
+        }
+      }
+      if (auto* ext = Properties::getSignExtValue(binary)) {
+        // use a cheaper zero-extent, we just care about the boolean value
+        // anyhow
+        return makeZeroExt(ext, Properties::getSignExtBits(binary));
+      }
+    } else if (auto* block = boolean->dynCast<Block>()) {
+      if (block->type == Type::i32 && block->list.size() > 0) {
+        block->list.back() = optimizeBoolean(block->list.back());
+      }
+    } else if (auto* iff = boolean->dynCast<If>()) {
+      if (iff->type == Type::i32) {
+        iff->ifTrue = optimizeBoolean(iff->ifTrue);
+        iff->ifFalse = optimizeBoolean(iff->ifFalse);
+      }
+    } else if (auto* select = boolean->dynCast<Select>()) {
+      select->ifTrue = optimizeBoolean(select->ifTrue);
+      select->ifFalse = optimizeBoolean(select->ifFalse);
+    } else if (auto* tryy = boolean->dynCast<Try>()) {
+      if (tryy->type == Type::i32) {
+        tryy->body = optimizeBoolean(tryy->body);
+        tryy->catchBody = optimizeBoolean(tryy->catchBody);
+      }
+    }
+    // TODO: recurse into br values?
+    return boolean;
+  }
+
+  Expression* optimizeSelect(Select* curr) {
+    using namespace Match;
+    Builder builder(*getModule());
+    curr->condition = optimizeBoolean(curr->condition);
+    {
+      // Constant condition, we can just pick the correct side (barring side
+      // effects)
+      Expression *ifTrue, *ifFalse;
+      if (matches(curr, select(pure(&ifTrue), any(&ifFalse), i32(0)))) {
+        return ifFalse;
+      }
+      if (matches(curr, select(any(&ifTrue), any(&ifFalse), i32(0)))) {
+        return builder.makeSequence(builder.makeDrop(ifTrue), ifFalse);
+      }
+      int32_t cond;
+      if (matches(curr, select(any(&ifTrue), pure(&ifFalse), i32(&cond)))) {
+        // The condition must be non-zero because a zero would have matched one
+        // of the previous patterns.
+        assert(cond != 0);
+        return ifTrue;
+      }
+      // Don't bother when `ifFalse` isn't pure - we would need to reverse the
+      // order using a temp local, which would be bad
+    }
+    {
+      // Flip select to remove eqz if we can reorder
+      Select* s;
+      Expression *ifTrue, *ifFalse, *c;
+      if (matches(
+            curr,
+            select(
+              &s, any(&ifTrue), any(&ifFalse), unary(EqZInt32, any(&c)))) &&
+          canReorder(ifTrue, ifFalse)) {
+        s->ifTrue = ifFalse;
+        s->ifFalse = ifTrue;
+        s->condition = c;
+      }
+    }
+    {
+      // Simplify selects between 0 and 1
+      Expression* c;
+      bool reversed = matches(curr, select(ival(0), ival(1), any(&c)));
+      if (reversed || matches(curr, select(ival(1), ival(0), any(&c)))) {
+        if (reversed) {
+          c = optimizeBoolean(builder.makeUnary(EqZInt32, c));
+        }
+        if (!Properties::emitsBoolean(c)) {
+          // cond ? 1 : 0 ==> !!cond
+          c = builder.makeUnary(EqZInt32, builder.makeUnary(EqZInt32, c));
+        }
+        return curr->type == Type::i64 ? builder.makeUnary(ExtendUInt32, c) : c;
+      }
+    }
+    {
+      // Sides are identical, fold
+      Expression *ifTrue, *ifFalse, *c;
+      if (matches(curr, select(any(&ifTrue), any(&ifFalse), any(&c))) &&
+          ExpressionAnalyzer::equal(ifTrue, ifFalse)) {
+        auto value = effects(ifTrue);
+        if (value.hasSideEffects()) {
+          // At best we don't need the condition, but need to execute the
+          // value twice. a block is larger than a select by 2 bytes, and we
+          // must drop one value, so 3, while we save the condition, so it's
+          // not clear this is worth it, TODO
+        } else {
+          // value has no side effects
+          auto condition = effects(c);
+          if (!condition.hasSideEffects()) {
+            return ifTrue;
+          } else {
+            // The condition is last, so we need a new local, and it may be a
+            // bad idea to use a block like we do for an if. Do it only if we
+            // can reorder
+            if (!condition.invalidates(value)) {
+              return builder.makeSequence(builder.makeDrop(c), ifTrue);
+            }
+          }
+        }
+      }
+    }
+    return nullptr;
+  }
+
+  // find added constants in an expression tree, including multiplied/shifted,
+  // and combine them note that we ignore division/shift-right, as rounding
+  // makes this nonlinear, so not a valid opt
+  Expression* optimizeAddedConstants(Binary* binary) {
+    assert(binary->type.isInteger());
+
+    uint64_t constant = 0;
+    std::vector<Const*> constants;
+
+    struct SeekState {
+      Expression* curr;
+      uint64_t mul;
+      SeekState(Expression* curr, uint64_t mul) : curr(curr), mul(mul) {}
+    };
+    std::vector<SeekState> seekStack;
+    seekStack.emplace_back(binary, 1);
+    while (!seekStack.empty()) {
+      auto state = seekStack.back();
+      seekStack.pop_back();
+      auto curr = state.curr;
+      auto mul = state.mul;
+      if (auto* c = curr->dynCast<Const>()) {
+        uint64_t value = c->value.getInteger();
+        if (value != 0ULL) {
+          constant += value * mul;
+          constants.push_back(c);
+        }
+        continue;
+      } else if (auto* binary = curr->dynCast<Binary>()) {
+        if (binary->op == Abstract::getBinary(binary->type, Abstract::Add)) {
+          seekStack.emplace_back(binary->right, mul);
+          seekStack.emplace_back(binary->left, mul);
+          continue;
+        } else if (binary->op ==
+                   Abstract::getBinary(binary->type, Abstract::Sub)) {
+          // if the left is a zero, ignore it, it's how we negate ints
+          auto* left = binary->left->dynCast<Const>();
+          seekStack.emplace_back(binary->right, -mul);
+          if (!left || !left->value.isZero()) {
+            seekStack.emplace_back(binary->left, mul);
+          }
+          continue;
+        } else if (binary->op ==
+                   Abstract::getBinary(binary->type, Abstract::Shl)) {
+          if (auto* c = binary->right->dynCast<Const>()) {
+            seekStack.emplace_back(binary->left,
+                                   mul << Bits::getEffectiveShifts(c));
+            continue;
+          }
+        } else if (binary->op ==
+                   Abstract::getBinary(binary->type, Abstract::Mul)) {
+          if (auto* c = binary->left->dynCast<Const>()) {
+            seekStack.emplace_back(binary->right,
+                                   mul * (uint64_t)c->value.getInteger());
+            continue;
+          } else if (auto* c = binary->right->dynCast<Const>()) {
+            seekStack.emplace_back(binary->left,
+                                   mul * (uint64_t)c->value.getInteger());
+            continue;
+          }
+        }
+      }
+    };
+    // find all factors
+    if (constants.size() <= 1) {
+      // nothing much to do, except for the trivial case of adding/subbing a
+      // zero
+      if (auto* c = binary->right->dynCast<Const>()) {
+        if (c->value.isZero()) {
+          return binary->left;
+        }
+      }
+      return nullptr;
+    }
+    // wipe out all constants, we'll replace with a single added one
+    for (auto* c : constants) {
+      c->value = Literal::makeZero(c->type);
+    }
+    // remove added/subbed zeros
+    struct ZeroRemover : public PostWalker<ZeroRemover> {
+      // TODO: we could save the binarys and costs we drop, and reuse them later
+
+      PassOptions& passOptions;
+
+      ZeroRemover(PassOptions& passOptions) : passOptions(passOptions) {}
+
+      void visitBinary(Binary* curr) {
+        if (!curr->type.isInteger()) {
+          return;
+        }
+        FeatureSet features = getModule()->features;
+        auto type = curr->type;
+        auto* left = curr->left->dynCast<Const>();
+        auto* right = curr->right->dynCast<Const>();
+        // Canonicalization prefers an add instead of a subtract wherever
+        // possible. That prevents a subtracted constant on the right,
+        // as it would be added. And for a zero on the left, it can't be
+        // removed (it is how we negate ints).
+        if (curr->op == Abstract::getBinary(type, Abstract::Add)) {
+          if (left && left->value.isZero()) {
+            replaceCurrent(curr->right);
+            return;
+          }
+          if (right && right->value.isZero()) {
+            replaceCurrent(curr->left);
+            return;
+          }
+        } else if (curr->op == Abstract::getBinary(type, Abstract::Shl)) {
+          // shifting a 0 is a 0, or anything by 0 has no effect, all unless the
+          // shift has side effects
+          if (((left && left->value.isZero()) ||
+               (right && Bits::getEffectiveShifts(right) == 0)) &&
+              !EffectAnalyzer(passOptions, features, curr->right)
+                 .hasSideEffects()) {
+            replaceCurrent(curr->left);
+            return;
+          }
+        } else if (curr->op == Abstract::getBinary(type, Abstract::Mul)) {
+          // multiplying by zero is a zero, unless the other side has side
+          // effects
+          if (left && left->value.isZero() &&
+              !EffectAnalyzer(passOptions, features, curr->right)
+                 .hasSideEffects()) {
+            replaceCurrent(left);
+            return;
+          }
+          if (right && right->value.isZero() &&
+              !EffectAnalyzer(passOptions, features, curr->left)
+                 .hasSideEffects()) {
+            replaceCurrent(right);
+            return;
+          }
+        }
+      }
+    };
+    Expression* walked = binary;
+    ZeroRemover remover(getPassOptions());
+    remover.setModule(getModule());
+    remover.walk(walked);
+    if (constant == 0ULL) {
+      return walked; // nothing more to do
+    }
+    if (auto* c = walked->dynCast<Const>()) {
+      assert(c->value.isZero());
+      // Accumulated 64-bit constant value in 32-bit context will be wrapped
+      // during downcasting. So it's valid unification for 32-bit and 64-bit
+      // values.
+      c->value = Literal::makeFromInt64(constant, c->type);
+      return c;
+    }
+    Builder builder(*getModule());
+    return builder.makeBinary(
+      Abstract::getBinary(walked->type, Abstract::Add),
+      walked,
+      builder.makeConst(Literal::makeFromInt64(constant, walked->type)));
+  }
+
+  //   expensive1 | expensive2 can be turned into expensive1 ? 1 : expensive2,
+  //   and expensive | cheap     can be turned into cheap     ? 1 : expensive,
+  // so that we can avoid one expensive computation, if it has no side effects.
+  Expression* conditionalizeExpensiveOnBitwise(Binary* binary) {
+    // this operation can increase code size, so don't always do it
+    auto& options = getPassRunner()->options;
+    if (options.optimizeLevel < 2 || options.shrinkLevel > 0) {
+      return nullptr;
+    }
+    const auto MIN_COST = 7;
+    assert(binary->op == AndInt32 || binary->op == OrInt32);
+    if (binary->right->is<Const>()) {
+      return nullptr; // trivial
+    }
+    // bitwise logical operator on two non-numerical values, check if they are
+    // boolean
+    auto* left = binary->left;
+    auto* right = binary->right;
+    if (!Properties::emitsBoolean(left) || !Properties::emitsBoolean(right)) {
+      return nullptr;
+    }
+    auto leftEffects = effects(left);
+    auto rightEffects = effects(right);
+    auto leftHasSideEffects = leftEffects.hasSideEffects();
+    auto rightHasSideEffects = rightEffects.hasSideEffects();
+    if (leftHasSideEffects && rightHasSideEffects) {
+      return nullptr; // both must execute
+    }
+    // canonicalize with side effects, if any, happening on the left
+    if (rightHasSideEffects) {
+      if (CostAnalyzer(left).cost < MIN_COST) {
+        return nullptr; // avoidable code is too cheap
+      }
+      if (leftEffects.invalidates(rightEffects)) {
+        return nullptr; // cannot reorder
+      }
+      std::swap(left, right);
+    } else if (leftHasSideEffects) {
+      if (CostAnalyzer(right).cost < MIN_COST) {
+        return nullptr; // avoidable code is too cheap
+      }
+    } else {
+      // no side effects, reorder based on cost estimation
+      auto leftCost = CostAnalyzer(left).cost;
+      auto rightCost = CostAnalyzer(right).cost;
+      if (std::max(leftCost, rightCost) < MIN_COST) {
+        return nullptr; // avoidable code is too cheap
+      }
+      // canonicalize with expensive code on the right
+      if (leftCost > rightCost) {
+        std::swap(left, right);
+      }
+    }
+    // worth it! perform conditionalization
+    Builder builder(*getModule());
+    if (binary->op == OrInt32) {
+      return builder.makeIf(
+        left, builder.makeConst(Literal(int32_t(1))), right);
+    } else { // &
+      return builder.makeIf(
+        left, right, builder.makeConst(Literal(int32_t(0))));
+    }
+  }
+
+  // We can combine `or` operations, e.g.
+  //   (x > y) | (x == y)    ==>    x >= y
+  Expression* combineOr(Binary* binary) {
+    assert(binary->op == OrInt32);
+    if (auto* left = binary->left->dynCast<Binary>()) {
+      if (auto* right = binary->right->dynCast<Binary>()) {
+        if (left->op != right->op &&
+            ExpressionAnalyzer::equal(left->left, right->left) &&
+            ExpressionAnalyzer::equal(left->right, right->right) &&
+            !effects(left->left).hasSideEffects() &&
+            !effects(left->right).hasSideEffects()) {
+          switch (left->op) {
+            //   (x > y) | (x == y)    ==>    x >= y
+            case EqInt32: {
+              if (right->op == GtSInt32) {
+                left->op = GeSInt32;
+                return left;
+              }
+              break;
+            }
+            default: {
+            }
+          }
+        }
+      }
+    }
+    return nullptr;
+  }
+
+  // fold constant factors into the offset
+  void optimizeMemoryAccess(Expression*& ptr, Address& offset) {
+    // ptr may be a const, but it isn't worth folding that in (we still have a
+    // const); in fact, it's better to do the opposite for gzip purposes as well
+    // as for readability.
+    auto* last = ptr->dynCast<Const>();
+    if (last) {
+      uint64_t value64 = last->value.getInteger();
+      uint64_t offset64 = offset;
+      if (getModule()->memory.is64()) {
+        last->value = Literal(int64_t(value64 + offset64));
+        offset = 0;
+      } else {
+        // don't do this if it would wrap the pointer
+        if (value64 <= uint64_t(std::numeric_limits<int32_t>::max()) &&
+            offset64 <= uint64_t(std::numeric_limits<int32_t>::max()) &&
+            value64 + offset64 <=
+              uint64_t(std::numeric_limits<int32_t>::max())) {
+          last->value = Literal(int32_t(value64 + offset64));
+          offset = 0;
+        }
+      }
+    }
+  }
+
+  // Optimize a multiply by a power of two on the right, which
+  // can be a shift.
+  // This doesn't shrink code size, and VMs likely optimize it anyhow,
+  // but it's still worth doing since
+  //  * Often shifts are more common than muls.
+  //  * The constant is smaller.
+  template<typename T> Expression* optimizePowerOf2Mul(Binary* binary, T c) {
+    static_assert(std::is_same<T, uint32_t>::value ||
+                    std::is_same<T, uint64_t>::value,
+                  "type mismatch");
+    auto shifts = Bits::countTrailingZeroes(c);
+    binary->op = std::is_same<T, uint32_t>::value ? ShlInt32 : ShlInt64;
+    binary->right->cast<Const>()->value = Literal(static_cast<T>(shifts));
+    return binary;
+  }
+
+  // Optimize an unsigned divide / remainder by a power of two on the right
+  // This doesn't shrink code size, and VMs likely optimize it anyhow,
+  // but it's still worth doing since
+  //  * Usually ands are more common than urems.
+  //  * The constant is slightly smaller.
+  template<typename T> Expression* optimizePowerOf2URem(Binary* binary, T c) {
+    static_assert(std::is_same<T, uint32_t>::value ||
+                    std::is_same<T, uint64_t>::value,
+                  "type mismatch");
+    binary->op = std::is_same<T, uint32_t>::value ? AndInt32 : AndInt64;
+    binary->right->cast<Const>()->value = Literal(c - 1);
+    return binary;
+  }
+
+  template<typename T> Expression* optimizePowerOf2UDiv(Binary* binary, T c) {
+    static_assert(std::is_same<T, uint32_t>::value ||
+                    std::is_same<T, uint64_t>::value,
+                  "type mismatch");
+    auto shifts = Bits::countTrailingZeroes(c);
+    binary->op = std::is_same<T, uint32_t>::value ? ShrUInt32 : ShrUInt64;
+    binary->right->cast<Const>()->value = Literal(static_cast<T>(shifts));
+    return binary;
+  }
+
+  template<typename T> Expression* optimizePowerOf2FDiv(Binary* binary, T c) {
+    //
+    // x / C_pot    =>   x * (C_pot ^ -1)
+    //
+    // Explanation:
+    // Floating point numbers are represented as:
+    //    ((-1) ^ sign) * (2 ^ (exp - bias)) * (1 + significand)
+    //
+    // If we have power of two numbers, then the mantissa (significand)
+    // is all zeros. Let's focus on the exponent, ignoring the sign part:
+    //    (2 ^ (exp - bias))
+    //
+    // and for inverted power of two floating point:
+    //     1.0 / (2 ^ (exp - bias))   ->   2 ^ -(exp - bias)
+    //
+    // So inversion of C_pot is valid because it changes only the sign
+    // of the exponent part and doesn't touch the significand part,
+    // which remains the same (zeros).
+    static_assert(std::is_same<T, float>::value ||
+                    std::is_same<T, double>::value,
+                  "type mismatch");
+    double invDivisor = 1.0 / (double)c;
+    binary->op = std::is_same<T, float>::value ? MulFloat32 : MulFloat64;
+    binary->right->cast<Const>()->value = Literal(static_cast<T>(invDivisor));
+    return binary;
+  }
+
+  Expression* makeZeroExt(Expression* curr, int32_t bits) {
+    Builder builder(*getModule());
+    return builder.makeBinary(
+      AndInt32, curr, builder.makeConst(Literal(Bits::lowBitMask(bits))));
+  }
+
+  // given an "almost" sign extend - either a proper one, or it
+  // has too many shifts left - we remove the sign extend. If there are
+  // too many shifts, we split the shifts first, so this removes the
+  // two sign extend shifts and adds one (smaller one)
+  Expression* removeAlmostSignExt(Binary* outer) {
+    auto* inner = outer->left->cast<Binary>();
+    auto* outerConst = outer->right->cast<Const>();
+    auto* innerConst = inner->right->cast<Const>();
+    auto* value = inner->left;
+    if (outerConst->value == innerConst->value) {
+      return value;
+    }
+    // add a shift, by reusing the existing node
+    innerConst->value = innerConst->value.sub(outerConst->value);
+    return inner;
+  }
+
+  // check if an expression is already sign-extended
+  bool isSignExted(Expression* curr, Index bits) {
+    if (Properties::getSignExtValue(curr)) {
+      return Properties::getSignExtBits(curr) == bits;
+    }
+    if (auto* get = curr->dynCast<LocalGet>()) {
+      // check what we know about the local
+      return localInfo[get->index].signExtedBits == bits;
+    }
+    return false;
+  }
+
+  // optimize trivial math operations, given that the right side of a binary
+  // is a constant
+  Expression* optimizeWithConstantOnRight(Binary* curr) {
+    using namespace Match;
+    using namespace Abstract;
+    Builder builder(*getModule());
+    Expression* left;
+    auto* right = curr->right->cast<Const>();
+    auto type = curr->right->type;
+
+    // Operations on zero
+    if (matches(curr, binary(Shl, any(&left), ival(0))) ||
+        matches(curr, binary(ShrU, any(&left), ival(0))) ||
+        matches(curr, binary(ShrS, any(&left), ival(0))) ||
+        matches(curr, binary(Or, any(&left), ival(0))) ||
+        matches(curr, binary(Xor, any(&left), ival(0)))) {
+      return left;
+    }
+    if (matches(curr, binary(Mul, pure(&left), ival(0))) ||
+        matches(curr, binary(And, pure(&left), ival(0)))) {
+      return right;
+    }
+    // x == 0   ==>   eqz x
+    if (matches(curr, binary(Eq, any(&left), ival(0)))) {
+      return builder.makeUnary(Abstract::getUnary(type, EqZ), left);
+    }
+    // Operations on one
+    // (signed)x % 1   ==>   0
+    if (matches(curr, binary(RemS, pure(&left), ival(1)))) {
+      right->value = Literal::makeZero(type);
+      return right;
+    }
+    // (signed)x % C_pot != 0   ==>  (x & (abs(C_pot) - 1)) != 0
+    {
+      Const* c;
+      Binary* inner;
+      if (matches(curr,
+                  binary(Ne, binary(&inner, RemS, any(), ival(&c)), ival(0))) &&
+          (c->value.isSignedMin() ||
+           Bits::isPowerOf2(c->value.abs().getInteger()))) {
+        inner->op = Abstract::getBinary(c->type, And);
+        if (c->value.isSignedMin()) {
+          c->value = Literal::makeSignedMax(c->type);
+        } else {
+          c->value = c->value.abs().sub(Literal::makeOne(c->type));
+        }
+        return curr;
+      }
+    }
+    // i32(bool(x)) == 1  ==>  i32(bool(x))
+    // i32(bool(x)) != 0  ==>  i32(bool(x))
+    // i32(bool(x)) & 1   ==>  i32(bool(x))
+    // i64(bool(x)) & 1   ==>  i64(bool(x))
+    if ((matches(curr, binary(EqInt32, any(&left), i32(1))) ||
+         matches(curr, binary(NeInt32, any(&left), i32(0))) ||
+         matches(curr, binary(And, any(&left), ival(1)))) &&
+        Bits::getMaxBits(left, this) == 1) {
+      return left;
+    }
+    // i64(bool(x)) == 1  ==>  i32(bool(x))
+    // i64(bool(x)) != 0  ==>  i32(bool(x))
+    if ((matches(curr, binary(EqInt64, any(&left), i64(1))) ||
+         matches(curr, binary(NeInt64, any(&left), i64(0)))) &&
+        Bits::getMaxBits(left, this) == 1) {
+      return builder.makeUnary(WrapInt64, left);
+    }
+    // bool(x) != 1  ==>  !bool(x)
+    if (matches(curr, binary(Ne, any(&left), ival(1))) &&
+        Bits::getMaxBits(left, this) == 1) {
+      return builder.makeUnary(Abstract::getUnary(type, EqZ), left);
+    }
+    // bool(x) | 1  ==>  1
+    if (matches(curr, binary(Or, pure(&left), ival(1))) &&
+        Bits::getMaxBits(left, this) == 1) {
+      return right;
+    }
+
+    // Operations on all 1s
+    // x & -1   ==>   x
+    if (matches(curr, binary(And, any(&left), ival(-1)))) {
+      return left;
+    }
+    // x | -1   ==>   -1
+    if (matches(curr, binary(Or, pure(&left), ival(-1)))) {
+      return right;
+    }
+    // (signed)x % -1   ==>   0
+    if (matches(curr, binary(RemS, pure(&left), ival(-1)))) {
+      right->value = Literal::makeZero(type);
+      return right;
+    }
+    // i32(x) / i32.min_s   ==>   x == i32.min_s
+    if (matches(
+          curr,
+          binary(DivSInt32, any(), i32(std::numeric_limits<int32_t>::min())))) {
+      curr->op = EqInt32;
+      return curr;
+    }
+    // i64(x) / i64.min_s   ==>   i64(x == i64.min_s)
+    // only for zero shrink level
+    if (getPassOptions().shrinkLevel == 0 &&
+        matches(
+          curr,
+          binary(DivSInt64, any(), i64(std::numeric_limits<int64_t>::min())))) {
+      curr->op = EqInt64;
+      curr->type = Type::i32;
+      return Builder(*getModule()).makeUnary(ExtendUInt32, curr);
+    }
+    // (unsigned)x < 0   ==>   i32(0)
+    if (matches(curr, binary(LtU, pure(&left), ival(0)))) {
+      right->value = Literal::makeZero(Type::i32);
+      right->type = Type::i32;
+      return right;
+    }
+    // (unsigned)x <= -1  ==>   i32(1)
+    if (matches(curr, binary(LeU, pure(&left), ival(-1)))) {
+      right->value = Literal::makeOne(Type::i32);
+      right->type = Type::i32;
+      return right;
+    }
+    // (unsigned)x > -1   ==>   i32(0)
+    if (matches(curr, binary(GtU, pure(&left), ival(-1)))) {
+      right->value = Literal::makeZero(Type::i32);
+      right->type = Type::i32;
+      return right;
+    }
+    // (unsigned)x >= 0   ==>   i32(1)
+    if (matches(curr, binary(GeU, pure(&left), ival(0)))) {
+      right->value = Literal::makeOne(Type::i32);
+      right->type = Type::i32;
+      return right;
+    }
+    // (unsigned)x < -1   ==>   x != -1
+    // Friendlier to JS emitting as we don't need to write an unsigned -1 value
+    // which is large.
+    if (matches(curr, binary(LtU, any(), ival(-1)))) {
+      curr->op = Abstract::getBinary(type, Ne);
+      return curr;
+    }
+    // (unsigned)x <= 0   ==>   x == 0
+    if (matches(curr, binary(LeU, any(), ival(0)))) {
+      curr->op = Abstract::getBinary(type, Eq);
+      return curr;
+    }
+    // (unsigned)x > 0   ==>   x != 0
+    if (matches(curr, binary(GtU, any(), ival(0)))) {
+      curr->op = Abstract::getBinary(type, Ne);
+      return curr;
+    }
+    // (unsigned)x >= -1  ==>   x == -1
+    if (matches(curr, binary(GeU, any(), ival(-1)))) {
+      curr->op = Abstract::getBinary(type, Eq);
+      return curr;
+    }
+    {
+      Const* c;
+      // (signed)x < (i32|i64).min_s   ==>   i32(0)
+      if (matches(curr, binary(LtS, pure(&left), ival(&c))) &&
+          c->value.isSignedMin()) {
+        right->value = Literal::makeZero(Type::i32);
+        right->type = Type::i32;
+        return right;
+      }
+      // (signed)x <= (i32|i64).max_s   ==>   i32(1)
+      if (matches(curr, binary(LeS, pure(&left), ival(&c))) &&
+          c->value.isSignedMax()) {
+        right->value = Literal::makeOne(Type::i32);
+        right->type = Type::i32;
+        return right;
+      }
+      // (signed)x > (i32|i64).max_s   ==>   i32(0)
+      if (matches(curr, binary(GtS, pure(&left), ival(&c))) &&
+          c->value.isSignedMax()) {
+        right->value = Literal::makeZero(Type::i32);
+        right->type = Type::i32;
+        return right;
+      }
+      // (signed)x >= (i32|i64).min_s   ==>   i32(1)
+      if (matches(curr, binary(GeS, pure(&left), ival(&c))) &&
+          c->value.isSignedMin()) {
+        right->value = Literal::makeOne(Type::i32);
+        right->type = Type::i32;
+        return right;
+      }
+      // (signed)x < (i32|i64).max_s   ==>   x != (i32|i64).max_s
+      if (matches(curr, binary(LtS, any(), ival(&c))) &&
+          c->value.isSignedMax()) {
+        curr->op = Abstract::getBinary(type, Ne);
+        return curr;
+      }
+      // (signed)x <= (i32|i64).min_s   ==>   x == (i32|i64).min_s
+      if (matches(curr, binary(LeS, any(), ival(&c))) &&
+          c->value.isSignedMin()) {
+        curr->op = Abstract::getBinary(type, Eq);
+        return curr;
+      }
+      // (signed)x > (i32|i64).min_s   ==>   x != (i32|i64).min_s
+      if (matches(curr, binary(GtS, any(), ival(&c))) &&
+          c->value.isSignedMin()) {
+        curr->op = Abstract::getBinary(type, Ne);
+        return curr;
+      }
+      // (signed)x >= (i32|i64).max_s   ==>   x == (i32|i64).max_s
+      if (matches(curr, binary(GeS, any(), ival(&c))) &&
+          c->value.isSignedMax()) {
+        curr->op = Abstract::getBinary(type, Eq);
+        return curr;
+      }
+    }
+    // x * -1   ==>   0 - x
+    if (matches(curr, binary(Mul, any(&left), ival(-1)))) {
+      right->value = Literal::makeZero(type);
+      curr->op = Abstract::getBinary(type, Sub);
+      curr->left = right;
+      curr->right = left;
+      return curr;
+    }
+    {
+      // ~(1 << x) aka (1 << x) ^ -1  ==>  rotl(-2, x)
+      Expression* x;
+      if (matches(curr, binary(Xor, binary(Shl, ival(1), any(&x)), ival(-1)))) {
+        curr->op = Abstract::getBinary(type, RotL);
+        right->value = Literal::makeFromInt32(-2, type);
+        curr->left = right;
+        curr->right = x;
+        return curr;
+      }
+    }
+    {
+      double value;
+      if (matches(curr, binary(Sub, any(), fval(&value))) && value == 0.0) {
+        // x - (-0.0)   ==>   x + 0.0
+        if (std::signbit(value)) {
+          curr->op = Abstract::getBinary(type, Add);
+          right->value = right->value.neg();
+          return curr;
+        } else if (fastMath) {
+          // x - 0.0   ==>   x
+          return curr->left;
+        }
+      }
+    }
+    {
+      // x * 2.0  ==>  x + x
+      // but we apply this only for simple expressions like
+      // local.get and global.get for avoid using extra local
+      // variable.
+      Expression* x;
+      if (matches(curr, binary(Mul, any(&x), fval(2.0))) &&
+          (x->is<LocalGet>() || x->is<GlobalGet>())) {
+        curr->op = Abstract::getBinary(type, Abstract::Add);
+        curr->right = ExpressionManipulator::copy(x, *getModule());
+        return curr;
+      }
+    }
+    {
+      // x + (-0.0)   ==>   x
+      double value;
+      if (fastMath && matches(curr, binary(Add, any(), fval(&value))) &&
+          value == 0.0 && std::signbit(value)) {
+        return curr->left;
+      }
+    }
+    // -x * fval(C)   ==>   x * -C
+    // -x / fval(C)   ==>   x / -C
+    if (matches(curr, binary(Mul, unary(Neg, any(&left)), fval())) ||
+        matches(curr, binary(DivS, unary(Neg, any(&left)), fval()))) {
+      right->value = right->value.neg();
+      curr->left = left;
+      return curr;
+    }
+    // x * -1.0   ==>
+    //       -x,  if fastMath == true
+    // -0.0 - x,  if fastMath == false
+    if (matches(curr, binary(Mul, any(), fval(-1.0)))) {
+      if (fastMath) {
+        return builder.makeUnary(Abstract::getUnary(type, Neg), left);
+      }
+      // x * -1.0   ==>  -0.0 - x
+      curr->op = Abstract::getBinary(type, Sub);
+      right->value = Literal::makeZero(type).neg();
+      std::swap(curr->left, curr->right);
+      return curr;
+    }
+    if (matches(curr, binary(Mul, any(&left), constant(1))) ||
+        matches(curr, binary(DivS, any(&left), constant(1))) ||
+        matches(curr, binary(DivU, any(&left), constant(1)))) {
+      if (curr->type.isInteger() || fastMath) {
+        return left;
+      }
+    }
+    return nullptr;
+  }
+
+  // optimize trivial math operations, given that the left side of a binary
+  // is a constant. since we canonicalize constants to the right for symmetrical
+  // operations, we only need to handle asymmetrical ones here
+  // TODO: templatize on type?
+  Expression* optimizeWithConstantOnLeft(Binary* curr) {
+    using namespace Match;
+    using namespace Abstract;
+
+    auto type = curr->left->type;
+    auto* left = curr->left->cast<Const>();
+    // 0 <<>> x   ==>   0
+    if (Abstract::hasAnyShift(curr->op) && left->value.isZero() &&
+        !effects(curr->right).hasSideEffects()) {
+      return curr->left;
+    }
+    // (signed)-1 >> x   ==>   -1
+    // rotl(-1, x)       ==>   -1
+    // rotr(-1, x)       ==>   -1
+    if ((curr->op == Abstract::getBinary(type, ShrS) ||
+         curr->op == Abstract::getBinary(type, RotL) ||
+         curr->op == Abstract::getBinary(type, RotR)) &&
+        left->value.getInteger() == -1LL &&
+        !effects(curr->right).hasSideEffects()) {
+      return curr->left;
+    }
+    {
+      // C1 - (x + C2)  ==>  (C1 - C2) - x
+      Const *c1, *c2;
+      Expression* x;
+      if (matches(curr,
+                  binary(Sub, ival(&c1), binary(Add, any(&x), ival(&c2))))) {
+        left->value = c1->value.sub(c2->value);
+        curr->right = x;
+        return curr;
+      }
+      // C1 - (C2 - x)  ==>   x + (C1 - C2)
+      if (matches(curr,
+                  binary(Sub, ival(&c1), binary(Sub, ival(&c2), any(&x))))) {
+        left->value = c1->value.sub(c2->value);
+        curr->op = Abstract::getBinary(type, Add);
+        curr->right = x;
+        std::swap(curr->left, curr->right);
+        return curr;
+      }
+    }
+    {
+      // fval(C) / -x   ==>  -C / x
+      Expression* right;
+      if (matches(curr, binary(DivS, fval(), unary(Neg, any(&right))))) {
+        left->value = left->value.neg();
+        curr->right = right;
+        return curr;
+      }
+    }
+    return nullptr;
+  }
+
+  // TODO: templatize on type?
+  Expression* optimizeRelational(Binary* curr) {
+    auto type = curr->right->type;
+    if (curr->left->type.isInteger()) {
+      if (curr->op == Abstract::getBinary(type, Abstract::Eq) ||
+          curr->op == Abstract::getBinary(type, Abstract::Ne)) {
+        if (auto* left = curr->left->dynCast<Binary>()) {
+          // TODO: inequalities can also work, if the constants do not overflow
+          // integer math, even on 2s complement, allows stuff like
+          // x + 5 == 7
+          //   =>
+          //     x == 2
+          if (left->op == Abstract::getBinary(type, Abstract::Add)) {
+            if (auto* leftConst = left->right->dynCast<Const>()) {
+              if (auto* rightConst = curr->right->dynCast<Const>()) {
+                return combineRelationalConstants(
+                  curr, left, leftConst, nullptr, rightConst);
+              } else if (auto* rightBinary = curr->right->dynCast<Binary>()) {
+                if (rightBinary->op ==
+                    Abstract::getBinary(type, Abstract::Add)) {
+                  if (auto* rightConst = rightBinary->right->dynCast<Const>()) {
+                    return combineRelationalConstants(
+                      curr, left, leftConst, rightBinary, rightConst);
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      // x - y == 0  =>  x == y
+      // x - y != 0  =>  x != y
+      // unsigned(x - y) > 0    =>   x != y
+      // unsigned(x - y) <= 0   =>   x == y
+      {
+        using namespace Abstract;
+        using namespace Match;
+
+        Binary* inner;
+        // unsigned(x - y) > 0    =>   x != y
+        if (matches(curr,
+                    binary(GtU, binary(&inner, Sub, any(), any()), ival(0)))) {
+          curr->op = Abstract::getBinary(type, Ne);
+          curr->right = inner->right;
+          curr->left = inner->left;
+          return curr;
+        }
+        // unsigned(x - y) <= 0   =>   x == y
+        if (matches(curr,
+                    binary(LeU, binary(&inner, Sub, any(), any()), ival(0)))) {
+          curr->op = Abstract::getBinary(type, Eq);
+          curr->right = inner->right;
+          curr->left = inner->left;
+          return curr;
+        }
+        // x - y == 0  =>  x == y
+        // x - y != 0  =>  x != y
+        // This is not true for signed comparisons like x -y < 0 due to overflow
+        // effects (e.g. 8 - 0x80000000 < 0 is not the same as 8 < 0x80000000).
+        if (matches(curr,
+                    binary(Eq, binary(&inner, Sub, any(), any()), ival(0))) ||
+            matches(curr,
+                    binary(Ne, binary(&inner, Sub, any(), any()), ival(0)))) {
+          curr->right = inner->right;
+          curr->left = inner->left;
+          return curr;
+        }
+      }
+    }
+    return nullptr;
+  }
+
+  Expression* deduplicateUnary(Unary* unaryOuter) {
+    if (auto* unaryInner = unaryOuter->value->dynCast<Unary>()) {
+      if (unaryInner->op == unaryOuter->op) {
+        switch (unaryInner->op) {
+          case NegFloat32:
+          case NegFloat64: {
+            // neg(neg(x))  ==>   x
+            return unaryInner->value;
+          }
+          case AbsFloat32:
+          case CeilFloat32:
+          case FloorFloat32:
+          case TruncFloat32:
+          case NearestFloat32:
+          case AbsFloat64:
+          case CeilFloat64:
+          case FloorFloat64:
+          case TruncFloat64:
+          case NearestFloat64: {
+            // unaryOp(unaryOp(x))  ==>   unaryOp(x)
+            return unaryInner;
+          }
+          case ExtendS8Int32:
+          case ExtendS16Int32: {
+            assert(getModule()->features.hasSignExt());
+            return unaryInner;
+          }
+          case EqZInt32: {
+            // eqz(eqz(bool(x)))  ==>   bool(x)
+            if (Bits::getMaxBits(unaryInner->value, this) == 1) {
+              return unaryInner->value;
+            }
+            break;
+          }
+          default: {
+          }
+        }
+      }
+    }
+    return nullptr;
+  }
+
+  Expression* deduplicateBinary(Binary* outer) {
+    Type type = outer->type;
+    if (type.isInteger()) {
+      if (auto* inner = outer->right->dynCast<Binary>()) {
+        if (outer->op == inner->op) {
+          if (!EffectAnalyzer(
+                 getPassOptions(), getModule()->features, outer->left)
+                 .hasSideEffects()) {
+            if (ExpressionAnalyzer::equal(inner->left, outer->left)) {
+              // x - (x - y)  ==>   y
+              // x ^ (x ^ y)  ==>   y
+              if (outer->op == Abstract::getBinary(type, Abstract::Sub) ||
+                  outer->op == Abstract::getBinary(type, Abstract::Xor)) {
+                return inner->right;
+              }
+              // x & (x & y)  ==>   x & y
+              // x | (x | y)  ==>   x | y
+              if (outer->op == Abstract::getBinary(type, Abstract::And) ||
+                  outer->op == Abstract::getBinary(type, Abstract::Or)) {
+                return inner;
+              }
+            }
+            if (ExpressionAnalyzer::equal(inner->right, outer->left) &&
+                canReorder(outer->left, inner->left)) {
+              // x ^ (y ^ x)  ==>   y
+              // (note that we need the check for reordering here because if
+              // e.g. y writes to a local that x reads, the second appearance
+              // of x would be different from the first)
+              if (outer->op == Abstract::getBinary(type, Abstract::Xor)) {
+                return inner->left;
+              }
+
+              // x & (y & x)  ==>   y & x
+              // x | (y | x)  ==>   y | x
+              // (here we need the check for reordering for the more obvious
+              // reason that previously x appeared before y, and now y appears
+              // first; or, if we tried to emit x [&|] y here, reversing the
+              // order, we'd be in the same situation as the previous comment)
+              if (outer->op == Abstract::getBinary(type, Abstract::And) ||
+                  outer->op == Abstract::getBinary(type, Abstract::Or)) {
+                return inner;
+              }
+            }
+          }
+        }
+      }
+      if (auto* inner = outer->left->dynCast<Binary>()) {
+        if (outer->op == inner->op) {
+          if (!EffectAnalyzer(
+                 getPassOptions(), getModule()->features, outer->right)
+                 .hasSideEffects()) {
+            if (ExpressionAnalyzer::equal(inner->right, outer->right)) {
+              // (x ^ y) ^ y  ==>   x
+              if (outer->op == Abstract::getBinary(type, Abstract::Xor)) {
+                return inner->left;
+              }
+              // (x % y) % y  ==>   x % y
+              // (x & y) & y  ==>   x & y
+              // (x | y) | y  ==>   x | y
+              if (outer->op == Abstract::getBinary(type, Abstract::RemS) ||
+                  outer->op == Abstract::getBinary(type, Abstract::RemU) ||
+                  outer->op == Abstract::getBinary(type, Abstract::And) ||
+                  outer->op == Abstract::getBinary(type, Abstract::Or)) {
+                return inner;
+              }
+            }
+            // See comments in the parallel code earlier about ordering here.
+            if (ExpressionAnalyzer::equal(inner->left, outer->right) &&
+                canReorder(inner->left, inner->right)) {
+              // (x ^ y) ^ x  ==>   y
+              if (outer->op == Abstract::getBinary(type, Abstract::Xor)) {
+                return inner->right;
+              }
+              // (x & y) & x  ==>   x & y
+              // (x | y) | x  ==>   x | y
+              if (outer->op == Abstract::getBinary(type, Abstract::And) ||
+                  outer->op == Abstract::getBinary(type, Abstract::Or)) {
+                return inner;
+              }
+            }
+          }
+        }
+      }
+    }
+    return nullptr;
+  }
+
+  // given a relational binary with a const on both sides, combine the constants
+  // left is also a binary, and has a constant; right may be just a constant, in
+  // which case right is nullptr
+  Expression* combineRelationalConstants(Binary* binary,
+                                         Binary* left,
+                                         Const* leftConst,
+                                         Binary* right,
+                                         Const* rightConst) {
+    auto type = binary->right->type;
+    // we fold constants to the right
+    Literal extra = leftConst->value;
+    if (left->op == Abstract::getBinary(type, Abstract::Sub)) {
+      extra = extra.neg();
+    }
+    if (right && right->op == Abstract::getBinary(type, Abstract::Sub)) {
+      extra = extra.neg();
+    }
+    rightConst->value = rightConst->value.sub(extra);
+    binary->left = left->left;
+    return binary;
+  }
+
+  Expression* optimizeMemoryCopy(MemoryCopy* memCopy) {
+    PassOptions options = getPassOptions();
+
+    if (options.ignoreImplicitTraps) {
+      if (ExpressionAnalyzer::equal(memCopy->dest, memCopy->source)) {
+        // memory.copy(x, x, sz)  ==>  {drop(x), drop(x), drop(sz)}
+        Builder builder(*getModule());
+        return builder.makeBlock({builder.makeDrop(memCopy->dest),
+                                  builder.makeDrop(memCopy->source),
+                                  builder.makeDrop(memCopy->size)});
+      }
+    }
+
+    // memory.copy(dst, src, C)  ==>  store(dst, load(src))
+    if (auto* csize = memCopy->size->dynCast<Const>()) {
+      auto bytes = csize->value.geti32();
+      Builder builder(*getModule());
+
+      switch (bytes) {
+        case 0: {
+          if (options.ignoreImplicitTraps) {
+            // memory.copy(dst, src, 0)  ==>  {drop(dst), drop(src)}
+            return builder.makeBlock({builder.makeDrop(memCopy->dest),
+                                      builder.makeDrop(memCopy->source)});
+          }
+          break;
+        }
+        case 1:
+        case 2:
+        case 4: {
+          return builder.makeStore(
+            bytes, // bytes
+            0,     // offset
+            1,     // align
+            memCopy->dest,
+            builder.makeLoad(bytes, false, 0, 1, memCopy->source, Type::i32),
+            Type::i32);
+        }
+        case 8: {
+          return builder.makeStore(
+            bytes, // bytes
+            0,     // offset
+            1,     // align
+            memCopy->dest,
+            builder.makeLoad(bytes, false, 0, 1, memCopy->source, Type::i64),
+            Type::i64);
+        }
+        case 16: {
+          if (options.shrinkLevel == 0) {
+            // This adds an extra 2 bytes so apply it only for
+            // minimal shrink level
+            if (getModule()->features.hasSIMD()) {
+              return builder.makeStore(
+                bytes, // bytes
+                0,     // offset
+                1,     // align
+                memCopy->dest,
+                builder.makeLoad(
+                  bytes, false, 0, 1, memCopy->source, Type::v128),
+                Type::v128);
+            }
+          }
+        }
+        default: {
+        }
+      }
+    }
+    return nullptr;
+  }
+
+  // given a binary expression with equal children and no side effects in
+  // either, we can fold various things
+  Expression* optimizeBinaryWithEqualEffectlessChildren(Binary* binary) {
+    // TODO add: perhaps worth doing 2*x if x is quite large?
+    switch (binary->op) {
+      case SubInt32:
+      case XorInt32:
+      case SubInt64:
+      case XorInt64:
+        return LiteralUtils::makeZero(binary->left->type, *getModule());
+      case NeInt32:
+      case LtSInt32:
+      case LtUInt32:
+      case GtSInt32:
+      case GtUInt32:
+      case NeInt64:
+      case LtSInt64:
+      case LtUInt64:
+      case GtSInt64:
+      case GtUInt64:
+        return LiteralUtils::makeZero(Type::i32, *getModule());
+      case AndInt32:
+      case OrInt32:
+      case AndInt64:
+      case OrInt64:
+        return binary->left;
+      case EqInt32:
+      case LeSInt32:
+      case LeUInt32:
+      case GeSInt32:
+      case GeUInt32:
+      case EqInt64:
+      case LeSInt64:
+      case LeUInt64:
+      case GeSInt64:
+      case GeUInt64:
+        return LiteralUtils::makeFromInt32(1, Type::i32, *getModule());
+      default:
+        return nullptr;
+    }
+  }
+
+  BinaryOp invertBinaryOp(BinaryOp op) {
+    // use de-morgan's laws
+    switch (op) {
+      case EqInt32:
+        return NeInt32;
+      case NeInt32:
+        return EqInt32;
+      case LtSInt32:
+        return GeSInt32;
+      case LtUInt32:
+        return GeUInt32;
+      case LeSInt32:
+        return GtSInt32;
+      case LeUInt32:
+        return GtUInt32;
+      case GtSInt32:
+        return LeSInt32;
+      case GtUInt32:
+        return LeUInt32;
+      case GeSInt32:
+        return LtSInt32;
+      case GeUInt32:
+        return LtUInt32;
+
+      case EqInt64:
+        return NeInt64;
+      case NeInt64:
+        return EqInt64;
+      case LtSInt64:
+        return GeSInt64;
+      case LtUInt64:
+        return GeUInt64;
+      case LeSInt64:
+        return GtSInt64;
+      case LeUInt64:
+        return GtUInt64;
+      case GtSInt64:
+        return LeSInt64;
+      case GtUInt64:
+        return LeUInt64;
+      case GeSInt64:
+        return LtSInt64;
+      case GeUInt64:
+        return LtUInt64;
+
+      case EqFloat32:
+        return NeFloat32;
+      case NeFloat32:
+        return EqFloat32;
+
+      case EqFloat64:
+        return NeFloat64;
+      case NeFloat64:
+        return EqFloat64;
+
+      default:
+        return InvalidBinary;
+    }
+  }
+
+  BinaryOp reverseRelationalOp(BinaryOp op) {
+    switch (op) {
+      case EqInt32:
+        return EqInt32;
+      case NeInt32:
+        return NeInt32;
+      case LtSInt32:
+        return GtSInt32;
+      case LtUInt32:
+        return GtUInt32;
+      case LeSInt32:
+        return GeSInt32;
+      case LeUInt32:
+        return GeUInt32;
+      case GtSInt32:
+        return LtSInt32;
+      case GtUInt32:
+        return LtUInt32;
+      case GeSInt32:
+        return LeSInt32;
+      case GeUInt32:
+        return LeUInt32;
+
+      case EqInt64:
+        return EqInt64;
+      case NeInt64:
+        return NeInt64;
+      case LtSInt64:
+        return GtSInt64;
+      case LtUInt64:
+        return GtUInt64;
+      case LeSInt64:
+        return GeSInt64;
+      case LeUInt64:
+        return GeUInt64;
+      case GtSInt64:
+        return LtSInt64;
+      case GtUInt64:
+        return LtUInt64;
+      case GeSInt64:
+        return LeSInt64;
+      case GeUInt64:
+        return LeUInt64;
+
+      case EqFloat32:
+        return EqFloat32;
+      case NeFloat32:
+        return NeFloat32;
+      case LtFloat32:
+        return GtFloat32;
+      case LeFloat32:
+        return GeFloat32;
+      case GtFloat32:
+        return LtFloat32;
+      case GeFloat32:
+        return LeFloat32;
+
+      case EqFloat64:
+        return EqFloat64;
+      case NeFloat64:
+        return NeFloat64;
+      case LtFloat64:
+        return GtFloat64;
+      case LeFloat64:
+        return GeFloat64;
+      case GtFloat64:
+        return LtFloat64;
+      case GeFloat64:
+        return LeFloat64;
+
+      default:
+        return InvalidBinary;
+    }
+  }
+
+  BinaryOp makeUnsignedBinaryOp(BinaryOp op) {
+    switch (op) {
+      case DivSInt32:
+        return DivUInt32;
+      case RemSInt32:
+        return RemUInt32;
+      case ShrSInt32:
+        return ShrUInt32;
+      case LtSInt32:
+        return LtUInt32;
+      case LeSInt32:
+        return LeUInt32;
+      case GtSInt32:
+        return GtUInt32;
+      case GeSInt32:
+        return GeUInt32;
+
+      case DivSInt64:
+        return DivUInt64;
+      case RemSInt64:
+        return RemUInt64;
+      case ShrSInt64:
+        return ShrUInt64;
+      case LtSInt64:
+        return LtUInt64;
+      case LeSInt64:
+        return LeUInt64;
+      case GtSInt64:
+        return GtUInt64;
+      case GeSInt64:
+        return GeUInt64;
+
+      default:
+        return InvalidBinary;
+    }
+  }
+
+  bool shouldCanonicalize(Binary* binary) {
+    if ((binary->op == SubInt32 || binary->op == SubInt64) &&
+        binary->right->is<Const>() && !binary->left->is<Const>()) {
+      return true;
+    }
+    if (Properties::isSymmetric(binary) || binary->isRelational()) {
+      return true;
+    }
+    switch (binary->op) {
+      case AddFloat32:
+      case MulFloat32:
+      case AddFloat64:
+      case MulFloat64: {
+        // If the LHS is known to be non-NaN, the operands can commute.
+        // We don't care about the RHS because right now we only know if
+        // an expression is non-NaN if it is constant, but if the RHS is
+        // constant, then this expression is already canonicalized.
+        if (auto* c = binary->left->dynCast<Const>()) {
+          return !c->value.isNaN();
+        }
+        return false;
+      }
+      default:
+        return false;
+    }
+  }
+};
+
+Pass* createOptimizeInstructionsPass() { return new OptimizeInstructions; }
 
 } // namespace wasm
diff --git a/binaryen/src/passes/PickLoadSigns.cpp b/binaryen/src/passes/PickLoadSigns.cpp
--- a/binaryen/src/passes/PickLoadSigns.cpp
+++ b/binaryen/src/passes/PickLoadSigns.cpp
@@ -109,6 +109,10 @@
              load->bytes * 8)) { // unsigned usages exist but the wrong size
         continue;
       }
+      // Atomic operations are always unsigned, never signed.
+      if (load->isAtomic) {
+        continue;
+      }
       // we can pick the optimal one. our hope is to remove 2 items per
       // signed use (two shifts), so we factor that in
       load->signed_ = usage.signedUsages * 2 >= usage.unsignedUsages;
diff --git a/binaryen/src/passes/PostAssemblyScript.cpp b/binaryen/src/passes/PostAssemblyScript.cpp
--- a/binaryen/src/passes/PostAssemblyScript.cpp
+++ b/binaryen/src/passes/PostAssemblyScript.cpp
@@ -28,7 +28,6 @@
 #include <unordered_map>
 #include <unordered_set>
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
-#include "wasm-printing.h"
 #include <iostream>
 #endif
 
@@ -468,14 +467,14 @@
             if (allBalanced) {
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
               std::cerr << "  eliminating ";
-              WasmPrinter::printExpression(retain, std::cerr, true);
+              std::cerr << *retain << '\n';
               std::cerr << " reaching\n";
 #endif
               redundantRetains.insert(retainLocation);
               for (auto** getLocation : releaseLocations) {
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
                 std::cerr << "    ";
-                WasmPrinter::printExpression(*getLocation, std::cerr, true);
+                std::cerr << **getLocation << '\n';
                 std::cerr << "\n";
 #endif
                 redundantReleases.insert(getLocation);
@@ -483,28 +482,28 @@
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
             } else {
               std::cerr << "  cannot eliminate ";
-              WasmPrinter::printExpression(retain, std::cerr, true);
+              std::cerr << *retain << '\n';
               std::cerr << " - unbalanced\n";
 #endif
             }
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
           } else {
             std::cerr << "  cannot eliminate ";
-            WasmPrinter::printExpression(retain, std::cerr, true);
+            std::cerr << *retain << '\n';
             std::cerr << " - zero releases\n";
 #endif
           }
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
         } else {
           std::cerr << "  cannot eliminate ";
-          WasmPrinter::printExpression(retain, std::cerr, true);
+          std::cerr << *retain << '\n';
           std::cerr << " - retains allocation\n";
 #endif
         }
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
       } else {
         std::cerr << "  cannot eliminate ";
-        WasmPrinter::printExpression(retain, std::cerr, true);
+        std::cerr << *retain << '\n';
         std::cerr << " - reaches return\n";
 #endif
       }
@@ -560,7 +559,7 @@
               // __release(__retain(__alloc(...))) - unnecessary allocation
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
               std::cerr << "  finalizing ";
-              WasmPrinter::printExpression(curr, std::cerr, true);
+              std::cerr << *curr << '\n';
               std::cerr << " - unnecessary allocation\n";
 #endif
               Builder builder(*getModule());
@@ -574,7 +573,7 @@
           // __release(__retain(...)) - unnecessary pair
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
           std::cerr << "  finalizing ";
-          WasmPrinter::printExpression(curr, std::cerr, true);
+          std::cerr << *curr << '\n';
           std::cerr << " - unnecessary pair\n";
 #endif
           Builder builder(*getModule());
@@ -586,7 +585,7 @@
         // __release(42) - unnecessary static release
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
         std::cerr << "  finalizing ";
-        WasmPrinter::printExpression(curr, std::cerr, true);
+        std::cerr << *curr << '\n';
         std::cerr << " - static release\n";
 #endif
         Builder builder(*getModule());
@@ -598,7 +597,7 @@
         // __retain(42) - unnecessary static retain
 #ifdef POST_ASSEMBLYSCRIPT_DEBUG
         std::cerr << "  finalizing ";
-        WasmPrinter::printExpression(curr, std::cerr, true);
+        std::cerr << *curr << '\n';
         std::cerr << " - static retain\n";
 #endif
         replaceCurrent(retainedConst);
diff --git a/binaryen/src/passes/PostEmscripten.cpp b/binaryen/src/passes/PostEmscripten.cpp
--- a/binaryen/src/passes/PostEmscripten.cpp
+++ b/binaryen/src/passes/PostEmscripten.cpp
@@ -41,46 +41,10 @@
   return F->imported() && F->module == ENV && F->base.startsWith("invoke_");
 }
 
-struct OptimizeCalls : public WalkerPass<PostWalker<OptimizeCalls>> {
-  bool isFunctionParallel() override { return true; }
-
-  Pass* create() override { return new OptimizeCalls; }
-
-  void visitCall(Call* curr) {
-    // special asm.js imports can be optimized
-    auto* func = getModule()->getFunction(curr->target);
-    if (!func->imported()) {
-      return;
-    }
-    if (func->module == GLOBAL_MATH) {
-      if (func->base == POW) {
-        if (auto* exponent = curr->operands[1]->dynCast<Const>()) {
-          if (exponent->value == Literal(double(2.0))) {
-            // This is just a square operation, do a multiply
-            Localizer localizer(curr->operands[0], getFunction(), getModule());
-            Builder builder(*getModule());
-            replaceCurrent(builder.makeBinary(
-              MulFloat64,
-              localizer.expr,
-              builder.makeLocalGet(localizer.index, localizer.expr->type)));
-          } else if (exponent->value == Literal(double(0.5))) {
-            // This is just a square root operation
-            replaceCurrent(
-              Builder(*getModule()).makeUnary(SqrtFloat64, curr->operands[0]));
-          }
-        }
-      }
-    }
-  }
-};
-
 } // namespace
 
 struct PostEmscripten : public Pass {
   void run(PassRunner* runner, Module* module) override {
-    // Optimize calls
-    OptimizeCalls().run(runner, module);
-
     // Optimize exceptions
     optimizeExceptions(runner, module);
   }
@@ -122,12 +86,12 @@
         }
       });
 
-    // Assume an indirect call might throw.
+    // Assume a non-direct call might throw.
     analyzer.propagateBack(
       [](const Info& info) { return info.canThrow; },
       [](const Info& info) { return true; },
       [](Info& info, Function* reason) { info.canThrow = true; },
-      analyzer.IndirectCallsHaveProperty);
+      analyzer.NonDirectCallsHaveProperty);
 
     // Apply the information.
     struct OptimizeInvokes : public WalkerPass<PostWalker<OptimizeInvokes>> {
diff --git a/binaryen/src/passes/Precompute.cpp b/binaryen/src/passes/Precompute.cpp
--- a/binaryen/src/passes/Precompute.cpp
+++ b/binaryen/src/passes/Precompute.cpp
@@ -177,6 +177,9 @@
       if (flow.breakTo == NONCONSTANT_FLOW) {
         return;
       }
+      if (!canEmitConstantFor(flow.values)) {
+        return;
+      }
       if (flow.breakTo == RETURN_FLOW) {
         // this expression causes a return. if it's already a return, reuse the
         // node
@@ -223,6 +226,9 @@
   // Precompute an expression, returning a flow, which may be a constant
   // (that we can replace the expression with if replaceExpression is set).
   Flow precomputeExpression(Expression* curr, bool replaceExpression = true) {
+    if (!canEmitConstantFor(curr->type)) {
+      return Flow(NONCONSTANT_FLOW);
+    }
     try {
       return PrecomputingExpressionRunner(
                getModule(), getValues, replaceExpression)
@@ -337,6 +343,37 @@
         }
       }
     }
+  }
+
+  bool canEmitConstantFor(const Literals& values) {
+    for (auto& value : values) {
+      if (!canEmitConstantFor(value)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool canEmitConstantFor(const Literal& value) {
+    // A null is fine to emit a constant for - we'll emit a RefNull. Otherwise,
+    // see below about references to GC data.
+    if (value.isNull()) {
+      return true;
+    }
+    // A function is fine to emit a constant for - we'll emit a RefFunc, which
+    // is compact and immutable, so there can't be a problem.
+    if (value.type.isFunction()) {
+      return true;
+    }
+    return canEmitConstantFor(value.type);
+  }
+
+  bool canEmitConstantFor(Type type) {
+    // Don't try to precompute a reference. We can't replace it with a constant
+    // expression, as that would make a copy of it by value.
+    // For now, don't try to precompute an Rtt. TODO figure out when that would
+    // be safe and useful.
+    return !type.isRef() && !type.isRtt();
   }
 };
 
diff --git a/binaryen/src/passes/Print.cpp b/binaryen/src/passes/Print.cpp
--- a/binaryen/src/passes/Print.cpp
+++ b/binaryen/src/passes/Print.cpp
@@ -21,12 +21,22 @@
 #include <ir/module-utils.h>
 #include <pass.h>
 #include <pretty_printing.h>
-#include <wasm-printing.h>
 #include <wasm-stack.h>
 #include <wasm.h>
 
 namespace wasm {
 
+static std::ostream& printExpression(Expression* expression,
+                                     std::ostream& o,
+                                     bool minify = false,
+                                     bool full = false);
+
+static std::ostream&
+printStackInst(StackInst* inst, std::ostream& o, Function* func = nullptr);
+
+static std::ostream&
+printStackIR(StackIR* ir, std::ostream& o, Function* func = nullptr);
+
 namespace {
 
 bool isFullForced() {
@@ -57,6 +67,101 @@
   return printName(name, o);
 }
 
+static void
+printHeapTypeName(std::ostream& os, HeapType type, bool first = true);
+
+// Prints the name of a type. This output is guaranteed to not contain spaces.
+static void printTypeName(std::ostream& os, Type type) {
+  if (type.isBasic()) {
+    os << type;
+    return;
+  }
+  if (type.isRtt()) {
+    auto rtt = type.getRtt();
+    os << "rtt_";
+    if (rtt.hasDepth()) {
+      os << rtt.depth << '_';
+    }
+    printHeapTypeName(os, rtt.heapType);
+    return;
+  }
+  if (type.isTuple()) {
+    auto sep = "";
+    for (auto t : type) {
+      os << sep;
+      sep = "_";
+      printTypeName(os, t);
+    }
+    return;
+  }
+  if (type.isRef()) {
+    os << "ref";
+    if (type.isNullable()) {
+      os << "?";
+    }
+    os << "|";
+    printHeapTypeName(os, type.getHeapType(), false);
+    os << "|";
+    return;
+  }
+  WASM_UNREACHABLE("unsupported print type");
+}
+
+static void printFieldName(std::ostream& os, const Field& field) {
+  if (field.mutable_) {
+    os << "mut:";
+  }
+  if (field.type == Type::i32 && field.packedType != Field::not_packed) {
+    if (field.packedType == Field::i8) {
+      os << "i8";
+    } else if (field.packedType == Field::i16) {
+      os << "i16";
+    } else {
+      WASM_UNREACHABLE("invalid packed type");
+    }
+  } else {
+    printTypeName(os, field.type);
+  }
+}
+
+// Prints the name of a heap type. As with printTypeName, this output is
+// guaranteed to not contain spaces.
+static void printHeapTypeName(std::ostream& os, HeapType type, bool first) {
+  if (type.isBasic()) {
+    os << type;
+    return;
+  }
+  if (first) {
+    os << '$';
+  }
+  if (type.isSignature()) {
+    auto sig = type.getSignature();
+    printTypeName(os, sig.params);
+    if (first) {
+      os << "_=>_";
+    } else {
+      os << "_->_";
+    }
+    printTypeName(os, sig.results);
+  } else if (type.isStruct()) {
+    auto struct_ = type.getStruct();
+    os << "{";
+    auto sep = "";
+    for (auto& field : struct_.fields) {
+      os << sep;
+      sep = "_";
+      printFieldName(os, field);
+    }
+    os << "}";
+  } else if (type.isArray()) {
+    os << "[";
+    printFieldName(os, type.getArray().element);
+    os << "]";
+  } else {
+    os << type;
+  }
+}
+
 // Unlike the default format, tuple types in s-expressions should not have
 // commas.
 struct SExprType {
@@ -64,8 +169,8 @@
   SExprType(Type type) : type(type){};
 };
 
-static std::ostream& operator<<(std::ostream& o, const SExprType& localType) {
-  Type type = localType.type;
+static std::ostream& operator<<(std::ostream& o, const SExprType& sType) {
+  Type type = sType.type;
   if (type.isTuple()) {
     o << '(';
     auto sep = "";
@@ -74,35 +179,50 @@
       sep = " ";
     }
     o << ')';
+  } else if (type.isRtt()) {
+    auto rtt = type.getRtt();
+    o << "(rtt ";
+    if (rtt.hasDepth()) {
+      o << rtt.depth << ' ';
+    }
+    printHeapTypeName(o, rtt.heapType);
+    o << ')';
+  } else if (type.isRef() && !type.isBasic()) {
+    o << "(ref ";
+    if (type.isNullable()) {
+      o << "null ";
+    }
+    printHeapTypeName(o, type.getHeapType());
+    o << ')';
   } else {
-    o << type;
+    printTypeName(o, sType.type);
   }
   return o;
 }
 
-// Wrapper for printing signature names
-struct SigName {
-  Signature sig;
-  SigName(Signature sig) : sig(sig) {}
+// TODO: try to simplify or even remove this, as we may be able to do the same
+//       things with SExprType
+struct ResultTypeName {
+  Type type;
+  ResultTypeName(Type type) : type(type) {}
 };
 
-std::ostream& operator<<(std::ostream& os, SigName sigName) {
-  auto printType = [&](Type type) {
-    if (type == Type::none) {
-      os << "none";
-    } else {
-      auto sep = "";
-      for (const auto& t : type) {
-        os << sep << t;
-        sep = "_";
-      }
+std::ostream& operator<<(std::ostream& os, ResultTypeName typeName) {
+  auto type = typeName.type;
+  os << "(result ";
+  if (type.isTuple()) {
+    // Tuple types are not printed in parens, we can just emit them one after
+    // the other in the same list as the "result".
+    auto sep = "";
+    for (auto t : type) {
+      os << sep;
+      sep = " ";
+      os << SExprType(t);
     }
-  };
-
-  os << '$';
-  printType(sigName.sig.params);
-  os << "_=>_";
-  printType(sigName.sig.results);
+  } else {
+    os << SExprType(type);
+  }
+  os << ')';
   return os;
 }
 
@@ -131,13 +251,13 @@
       printName(curr->name, o);
     }
     if (curr->type.isConcrete()) {
-      o << ' ' << ResultType(curr->type);
+      o << ' ' << ResultTypeName(curr->type);
     }
   }
   void visitIf(If* curr) {
     printMedium(o, "if");
     if (curr->type.isConcrete()) {
-      o << ' ' << ResultType(curr->type);
+      o << ' ' << ResultTypeName(curr->type);
     }
   }
   void visitLoop(Loop* curr) {
@@ -147,7 +267,7 @@
       printName(curr->name, o);
     }
     if (curr->type.isConcrete()) {
-      o << ' ' << ResultType(curr->type);
+      o << ' ' << ResultTypeName(curr->type);
     }
   }
   void visitBreak(Break* curr) {
@@ -181,7 +301,8 @@
     } else {
       printMedium(o, "call_indirect (type ");
     }
-    o << SigName(curr->sig) << ')';
+    printHeapTypeName(o, curr->sig);
+    o << ')';
   }
   void visitLocalGet(LocalGet* curr) {
     printMedium(o, "local.get ");
@@ -274,22 +395,22 @@
     prepareColor(o);
     printRMWSize(o, curr->type, curr->bytes);
     switch (curr->op) {
-      case Add:
+      case RMWAdd:
         o << "add";
         break;
-      case Sub:
+      case RMWSub:
         o << "sub";
         break;
-      case And:
+      case RMWAnd:
         o << "and";
         break;
-      case Or:
+      case RMWOr:
         o << "or";
         break;
-      case Xor:
+      case RMWXor:
         o << "xor";
         break;
-      case Xchg:
+      case RMWXchg:
         o << "xchg";
         break;
     }
@@ -317,13 +438,15 @@
   }
   void visitAtomicWait(AtomicWait* curr) {
     prepareColor(o);
-    o << forceConcrete(curr->expectedType) << ".atomic.wait";
+    Type type = forceConcrete(curr->expectedType);
+    assert(type == Type::i32 || type == Type::i64);
+    o << "memory.atomic.wait" << (type == Type::i32 ? "32" : "64");
     if (curr->offset) {
       o << " offset=" << curr->offset;
     }
   }
   void visitAtomicNotify(AtomicNotify* curr) {
-    printMedium(o, "atomic.notify");
+    printMedium(o, "memory.atomic.notify");
     if (curr->offset) {
       o << " offset=" << curr->offset;
     }
@@ -408,6 +531,18 @@
       case QFMSF64x2:
         o << "f64x2.qfms";
         break;
+      case SignSelectVec8x16:
+        o << "v8x16.signselect";
+        break;
+      case SignSelectVec16x8:
+        o << "v16x8.signselect";
+        break;
+      case SignSelectVec32x4:
+        o << "v32x4.signselect";
+        break;
+      case SignSelectVec64x2:
+        o << "v64x2.signselect";
+        break;
     }
   }
   void visitSIMDShift(SIMDShift* curr) {
@@ -499,6 +634,61 @@
       o << " align=" << curr->align;
     }
   }
+  void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+    prepareColor(o);
+    switch (curr->op) {
+      case LoadLaneVec8x16:
+        o << "v128.load8_lane";
+        break;
+      case LoadLaneVec16x8:
+        o << "v128.load16_lane";
+        break;
+      case LoadLaneVec32x4:
+        o << "v128.load32_lane";
+        break;
+      case LoadLaneVec64x2:
+        o << "v128.load64_lane";
+        break;
+      case StoreLaneVec8x16:
+        o << "v128.store8_lane";
+        break;
+      case StoreLaneVec16x8:
+        o << "v128.store16_lane";
+        break;
+      case StoreLaneVec32x4:
+        o << "v128.store32_lane";
+        break;
+      case StoreLaneVec64x2:
+        o << "v128.store64_lane";
+        break;
+    }
+    restoreNormalColor(o);
+    if (curr->offset) {
+      o << " offset=" << curr->offset;
+    }
+    if (curr->align != curr->getMemBytes()) {
+      o << " align=" << curr->align;
+    }
+    o << " " << int(curr->index);
+  }
+  void visitPrefetch(Prefetch* curr) {
+    prepareColor(o);
+    switch (curr->op) {
+      case PrefetchTemporal:
+        o << "prefetch.t";
+        break;
+      case PrefetchNontemporal:
+        o << "prefetch.nt";
+        break;
+    }
+    restoreNormalColor(o);
+    if (curr->offset) {
+      o << " offset=" << curr->offset;
+    }
+    if (curr->align != 1) {
+      o << " align=" << curr->align;
+    }
+  }
   void visitMemoryInit(MemoryInit* curr) {
     prepareColor(o);
     o << "memory.init " << curr->segment;
@@ -737,6 +927,9 @@
       case BitmaskVecI8x16:
         o << "i8x16.bitmask";
         break;
+      case PopcntVecI8x16:
+        o << "i8x16.popcnt";
+        break;
       case AbsVecI16x8:
         o << "i16x8.abs";
         break;
@@ -770,11 +963,8 @@
       case NegVecI64x2:
         o << "i64x2.neg";
         break;
-      case AnyTrueVecI64x2:
-        o << "i64x2.any_true";
-        break;
-      case AllTrueVecI64x2:
-        o << "i64x2.all_true";
+      case BitmaskVecI64x2:
+        o << "i64x2.bitmask";
         break;
       case AbsVecF32x4:
         o << "f32x4.abs";
@@ -818,6 +1008,18 @@
       case NearestVecF64x2:
         o << "f64x2.nearest";
         break;
+      case ExtAddPairwiseSVecI8x16ToI16x8:
+        o << "i16x8.extadd_pairwise_i8x16_s";
+        break;
+      case ExtAddPairwiseUVecI8x16ToI16x8:
+        o << "i16x8.extadd_pairwise_i8x16_u";
+        break;
+      case ExtAddPairwiseSVecI16x8ToI32x4:
+        o << "i32x4.extadd_pairwise_i16x8_s";
+        break;
+      case ExtAddPairwiseUVecI16x8ToI32x4:
+        o << "i32x4.extadd_pairwise_i16x8_u";
+        break;
       case TruncSatSVecF32x4ToVecI32x4:
         o << "i32x4.trunc_sat_f32x4_s";
         break;
@@ -866,6 +1068,18 @@
       case WidenHighUVecI16x8ToVecI32x4:
         o << "i32x4.widen_high_i16x8_u";
         break;
+      case WidenLowSVecI32x4ToVecI64x2:
+        o << "i64x2.widen_low_i32x4_s";
+        break;
+      case WidenHighSVecI32x4ToVecI64x2:
+        o << "i64x2.widen_high_i32x4_s";
+        break;
+      case WidenLowUVecI32x4ToVecI64x2:
+        o << "i64x2.widen_low_i32x4_u";
+        break;
+      case WidenHighUVecI32x4ToVecI64x2:
+        o << "i64x2.widen_high_i32x4_u";
+        break;
       case InvalidUnary:
         WASM_UNREACHABLE("unvalid unary operator");
     }
@@ -1195,6 +1409,9 @@
       case GeUVecI32x4:
         o << "i32x4.ge_u";
         break;
+      case EqVecI64x2:
+        o << "i64x2.eq";
+        break;
       case EqVecF32x4:
         o << "f32x4.eq";
         break;
@@ -1317,6 +1534,22 @@
       case AvgrUVecI16x8:
         o << "i16x8.avgr_u";
         break;
+      case Q15MulrSatSVecI16x8:
+        o << "i16x8.q15mulr_sat_s";
+        break;
+      case ExtMulLowSVecI16x8:
+        o << "i16x8.extmul_low_i8x16_s";
+        break;
+      case ExtMulHighSVecI16x8:
+        o << "i16x8.extmul_high_i8x16_s";
+        break;
+      case ExtMulLowUVecI16x8:
+        o << "i16x8.extmul_low_i8x16_u";
+        break;
+      case ExtMulHighUVecI16x8:
+        o << "i16x8.extmul_high_i8x16_u";
+        break;
+
       case AddVecI32x4:
         o << "i32x4.add";
         break;
@@ -1341,6 +1574,19 @@
       case DotSVecI16x8ToVecI32x4:
         o << "i32x4.dot_i16x8_s";
         break;
+      case ExtMulLowSVecI32x4:
+        o << "i32x4.extmul_low_i16x8_s";
+        break;
+      case ExtMulHighSVecI32x4:
+        o << "i32x4.extmul_high_i16x8_s";
+        break;
+      case ExtMulLowUVecI32x4:
+        o << "i32x4.extmul_low_i16x8_u";
+        break;
+      case ExtMulHighUVecI32x4:
+        o << "i32x4.extmul_high_i16x8_u";
+        break;
+
       case AddVecI64x2:
         o << "i64x2.add";
         break;
@@ -1350,6 +1596,18 @@
       case MulVecI64x2:
         o << "i64x2.mul";
         break;
+      case ExtMulLowSVecI64x2:
+        o << "i64x2.extmul_low_i32x4_s";
+        break;
+      case ExtMulHighSVecI64x2:
+        o << "i64x2.extmul_high_i32x4_s";
+        break;
+      case ExtMulLowUVecI64x2:
+        o << "i64x2.extmul_low_i32x4_u";
+        break;
+      case ExtMulHighUVecI64x2:
+        o << "i64x2.extmul_high_i32x4_u";
+        break;
 
       case AddVecF32x4:
         o << "f32x4.add";
@@ -1425,7 +1683,7 @@
   void visitSelect(Select* curr) {
     prepareColor(o) << "select";
     if (curr->type.isRef()) {
-      o << " (result " << curr->type << ')';
+      o << ' ' << ResultTypeName(curr->type);
     }
   }
   void visitDrop(Drop* curr) { printMedium(o, "drop"); }
@@ -1434,7 +1692,7 @@
   void visitMemoryGrow(MemoryGrow* curr) { printMedium(o, "memory.grow"); }
   void visitRefNull(RefNull* curr) {
     printMedium(o, "ref.null ");
-    o << curr->type.getHeapType();
+    printHeapTypeName(o, curr->type.getHeapType());
   }
   void visitRefIsNull(RefIsNull* curr) { printMedium(o, "ref.is_null"); }
   void visitRefFunc(RefFunc* curr) {
@@ -1478,49 +1736,93 @@
   void visitI31Get(I31Get* curr) {
     printMedium(o, curr->signed_ ? "i31.get_s" : "i31.get_u");
   }
+  void visitCallRef(CallRef* curr) {
+    if (curr->isReturn) {
+      printMedium(o, "return_call_ref");
+    } else {
+      printMedium(o, "call_ref");
+    }
+  }
   void visitRefTest(RefTest* curr) {
-    printMedium(o, "ref.test");
-    WASM_UNREACHABLE("TODO (gc): ref.test");
+    printMedium(o, "ref.test ");
+    printHeapTypeName(o, curr->getCastType().getHeapType());
   }
   void visitRefCast(RefCast* curr) {
-    printMedium(o, "ref.cast");
-    WASM_UNREACHABLE("TODO (gc): ref.cast");
+    printMedium(o, "ref.cast ");
+    printHeapTypeName(o, curr->getCastType().getHeapType());
   }
   void visitBrOnCast(BrOnCast* curr) {
-    printMedium(o, "br_on_cast");
-    WASM_UNREACHABLE("TODO (gc): br_on_cast");
+    printMedium(o, "br_on_cast ");
+    printName(curr->name, o);
+    o << " ";
+    printHeapTypeName(o, curr->getCastType().getHeapType());
   }
   void visitRttCanon(RttCanon* curr) {
-    printMedium(o, "rtt.canon");
-    WASM_UNREACHABLE("TODO (gc): rtt.canon");
+    printMedium(o, "rtt.canon ");
+    printHeapTypeName(o, curr->type.getRtt().heapType);
   }
   void visitRttSub(RttSub* curr) {
-    printMedium(o, "rtt.sub");
-    WASM_UNREACHABLE("TODO (gc): rtt.sub");
+    printMedium(o, "rtt.sub ");
+    printHeapTypeName(o, curr->type.getRtt().heapType);
   }
   void visitStructNew(StructNew* curr) {
-    WASM_UNREACHABLE("TODO (gc): struct.new");
+    printMedium(o, "struct.new_");
+    if (curr->isWithDefault()) {
+      o << "default_";
+    }
+    o << "with_rtt ";
+    printHeapTypeName(o, curr->rtt->type.getHeapType());
   }
   void visitStructGet(StructGet* curr) {
-    WASM_UNREACHABLE("TODO (gc): struct.get");
+    const auto& field =
+      curr->ref->type.getHeapType().getStruct().fields[curr->index];
+    if (field.type == Type::i32 && field.packedType != Field::not_packed) {
+      if (curr->signed_) {
+        printMedium(o, "struct.get_s ");
+      } else {
+        printMedium(o, "struct.get_u ");
+      }
+    } else {
+      printMedium(o, "struct.get ");
+    }
+    printHeapTypeName(o, curr->ref->type.getHeapType());
+    o << ' ';
+    o << curr->index;
   }
   void visitStructSet(StructSet* curr) {
-    printMedium(o, "struct.set");
-    WASM_UNREACHABLE("TODO (gc): struct.set");
+    printMedium(o, "struct.set ");
+    printHeapTypeName(o, curr->ref->type.getHeapType());
+    o << ' ';
+    o << curr->index;
   }
   void visitArrayNew(ArrayNew* curr) {
-    WASM_UNREACHABLE("TODO (gc): array.new");
+    printMedium(o, "array.new_");
+    if (curr->isWithDefault()) {
+      o << "default_";
+    }
+    o << "with_rtt ";
+    printHeapTypeName(o, curr->rtt->type.getHeapType());
   }
   void visitArrayGet(ArrayGet* curr) {
-    WASM_UNREACHABLE("TODO (gc): array.get");
+    const auto& element = curr->ref->type.getHeapType().getArray().element;
+    if (element.type == Type::i32 && element.packedType != Field::not_packed) {
+      if (curr->signed_) {
+        printMedium(o, "array.get_s ");
+      } else {
+        printMedium(o, "array.get_u ");
+      }
+    } else {
+      printMedium(o, "array.get ");
+    }
+    printHeapTypeName(o, curr->ref->type.getHeapType());
   }
   void visitArraySet(ArraySet* curr) {
-    printMedium(o, "array.set");
-    WASM_UNREACHABLE("TODO (gc): array.set");
+    printMedium(o, "array.set ");
+    printHeapTypeName(o, curr->ref->type.getHeapType());
   }
   void visitArrayLen(ArrayLen* curr) {
-    printMedium(o, "array.len");
-    WASM_UNREACHABLE("TODO (gc): array.len");
+    printMedium(o, "array.len ");
+    printHeapTypeName(o, curr->ref->type.getHeapType());
   }
 };
 
@@ -1536,9 +1838,9 @@
 
   bool full = false; // whether to not elide nodes in output when possible
                      // (like implicit blocks) and to emit types
-  bool printStackIR = false; // whether to print stack IR if it is present
-                             // (if false, and Stack IR is there, we just
-                             // note it exists)
+  bool stackIR = false; // whether to print stack IR if it is present
+                        // (if false, and Stack IR is there, we just
+                        // note it exists)
 
   Module* currModule = nullptr;
   Function* currFunction = nullptr;
@@ -1598,7 +1900,7 @@
 
   void setFull(bool full_) { full = full_; }
 
-  void setPrintStackIR(bool printStackIR_) { printStackIR = printStackIR_; }
+  void setStackIR(bool stackIR_) { stackIR = stackIR_; }
 
   void setDebugInfo(bool debugInfo_) { debugInfo = debugInfo_; }
 
@@ -1908,6 +2210,21 @@
     printFullLine(curr->ptr);
     decIndent();
   }
+  void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->ptr);
+    printFullLine(curr->vec);
+    decIndent();
+  }
+  void visitPrefetch(Prefetch* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    printFullLine(curr->ptr);
+    decIndent();
+  }
   void visitMemoryInit(MemoryInit* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
@@ -2125,82 +2442,186 @@
     printFullLine(curr->i31);
     decIndent();
   }
+  void visitCallRef(CallRef* curr) {
+    o << '(';
+    PrintExpressionContents(currFunction, o).visit(curr);
+    incIndent();
+    for (auto operand : curr->operands) {
+      printFullLine(operand);
+    }
+    printFullLine(curr->target);
+    decIndent();
+  }
   void visitRefTest(RefTest* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): ref.test");
+    incIndent();
+    printFullLine(curr->ref);
+    printFullLine(curr->rtt);
+    decIndent();
   }
   void visitRefCast(RefCast* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): ref.cast");
+    incIndent();
+    printFullLine(curr->ref);
+    printFullLine(curr->rtt);
+    decIndent();
   }
   void visitBrOnCast(BrOnCast* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): br_on_cast");
+    incIndent();
+    printFullLine(curr->ref);
+    printFullLine(curr->rtt);
+    decIndent();
   }
   void visitRttCanon(RttCanon* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): rtt.canon");
+    o << ')';
   }
   void visitRttSub(RttSub* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): rtt.sub");
+    incIndent();
+    printFullLine(curr->parent);
+    decIndent();
   }
   void visitStructNew(StructNew* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): struct.new");
+    incIndent();
+    printFullLine(curr->rtt);
+    for (auto& operand : curr->operands) {
+      printFullLine(operand);
+    }
+    decIndent();
   }
   void visitStructGet(StructGet* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): struct.get");
+    incIndent();
+    printFullLine(curr->ref);
+    decIndent();
   }
   void visitStructSet(StructSet* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): struct.set");
+    incIndent();
+    printFullLine(curr->ref);
+    printFullLine(curr->value);
+    decIndent();
   }
   void visitArrayNew(ArrayNew* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): array.new");
+    incIndent();
+    printFullLine(curr->rtt);
+    printFullLine(curr->size);
+    if (curr->init) {
+      printFullLine(curr->init);
+    }
+    decIndent();
   }
   void visitArrayGet(ArrayGet* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): array.get");
+    incIndent();
+    printFullLine(curr->ref);
+    printFullLine(curr->index);
+    decIndent();
   }
   void visitArraySet(ArraySet* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): array.set");
+    incIndent();
+    printFullLine(curr->ref);
+    printFullLine(curr->index);
+    printFullLine(curr->value);
+    decIndent();
   }
   void visitArrayLen(ArrayLen* curr) {
     o << '(';
     PrintExpressionContents(currFunction, o).visit(curr);
-    WASM_UNREACHABLE("TODO (gc): array.len");
+    incIndent();
+    printFullLine(curr->ref);
+    decIndent();
   }
   // Module-level visitors
-  void handleSignature(Signature curr, Name* funcName = nullptr) {
+  void handleSignature(Signature curr, Name name = Name()) {
     o << "(func";
-    if (funcName) {
-      o << " $" << *funcName;
+    if (name.is()) {
+      o << " $" << name;
     }
     if (curr.params.size() > 0) {
       o << maybeSpace;
-      o << ParamType(curr.params);
+      o << "(param ";
+      auto sep = "";
+      for (auto type : curr.params) {
+        o << sep << SExprType(type);
+        sep = " ";
+      }
+      o << ')';
     }
     if (curr.results.size() > 0) {
       o << maybeSpace;
-      o << ResultType(curr.results);
+      o << "(result ";
+      auto sep = "";
+      for (auto type : curr.results) {
+        o << sep << SExprType(type);
+        sep = " ";
+      }
+      o << ')';
     }
     o << ")";
   }
+  void handleFieldBody(const Field& field) {
+    if (field.mutable_) {
+      o << "(mut ";
+    }
+    if (field.type == Type::i32 && field.packedType != Field::not_packed) {
+      if (field.packedType == Field::i8) {
+        o << "i8";
+      } else if (field.packedType == Field::i16) {
+        o << "i16";
+      } else {
+        WASM_UNREACHABLE("invalid packed type");
+      }
+    } else {
+      o << SExprType(field.type);
+    }
+    if (field.mutable_) {
+      o << ')';
+    }
+  }
+  void handleArray(const Array& curr) {
+    o << "(array ";
+    handleFieldBody(curr.element);
+    o << ')';
+  }
+  void handleStruct(const Struct& curr) {
+    o << "(struct ";
+    auto sep = "";
+    for (auto field : curr.fields) {
+      o << sep << "(field ";
+      handleFieldBody(field);
+      o << ')';
+      sep = " ";
+    }
+    o << ')';
+  }
+  void handleHeapType(HeapType type) {
+    if (type.isSignature()) {
+      handleSignature(type.getSignature());
+    } else if (type.isArray()) {
+      handleArray(type.getArray());
+    } else if (type.isStruct()) {
+      handleStruct(type.getStruct());
+    } else {
+      o << type;
+    }
+  }
   void visitExport(Export* curr) {
     o << '(';
     printMedium(o, "export ");
@@ -2279,7 +2700,7 @@
     lastPrintedLocation = {0, 0, 0};
     o << '(';
     emitImportHeader(curr);
-    handleSignature(curr->sig, &curr->name);
+    handleSignature(curr->sig, curr->name);
     o << ')';
     o << maybeNewLine;
   }
@@ -2293,7 +2714,7 @@
     o << '(';
     printMajor(o, "func ");
     printName(curr->name, o);
-    if (!printStackIR && curr->stackIR && !minify) {
+    if (!stackIR && curr->stackIR && !minify) {
       o << " (; has Stack IR ;)";
     }
     if (curr->sig.params.size() > 0) {
@@ -2303,13 +2724,13 @@
         o << '(';
         printMinor(o, "param ");
         printLocal(i, currFunction, o);
-        o << ' ' << param << ')';
+        o << ' ' << SExprType(param) << ')';
         ++i;
       }
     }
     if (curr->sig.results != Type::none) {
       o << maybeSpace;
-      o << ResultType(curr->sig.results);
+      o << ResultTypeName(curr->sig.results);
     }
     incIndent();
     for (size_t i = curr->getVarIndexBase(); i < curr->getNumLocals(); i++) {
@@ -2321,7 +2742,7 @@
       o << maybeNewLine;
     }
     // Print the body.
-    if (!printStackIR || !curr->stackIR) {
+    if (!stackIR || !curr->stackIR) {
       // It is ok to emit a block here, as a function can directly contain a
       // list, even if our ast avoids that for simplicity. We can just do that
       // optimization here..
@@ -2336,7 +2757,7 @@
       }
     } else {
       // Print the stack IR.
-      WasmPrinter::printStackIR(curr->stackIR.get(), o, curr);
+      printStackIR(curr->stackIR.get(), o, curr);
     }
     if (currFunction->epilogLocation.size() &&
         lastPrintedLocation != *currFunction->epilogLocation.begin()) {
@@ -2460,6 +2881,10 @@
       doIndent(o, indent);
       o << '(';
       printMajor(o, "data ");
+      if (segment.name.is()) {
+        printName(segment.name, o);
+        o << ' ';
+      }
       if (segment.isPassive) {
         printMedium(o, "passive");
       } else {
@@ -2528,15 +2953,16 @@
       printName(curr->name, o);
     }
     incIndent();
-    std::vector<Signature> signatures;
-    std::unordered_map<Signature, Index> indices;
-    ModuleUtils::collectSignatures(*curr, signatures, indices);
-    for (auto sig : signatures) {
+    std::vector<HeapType> types;
+    std::unordered_map<HeapType, Index> indices;
+    ModuleUtils::collectHeapTypes(*curr, types, indices);
+    for (auto type : types) {
       doIndent(o, indent);
       o << '(';
       printMedium(o, "type") << ' ';
-      o << SigName(sig) << ' ';
-      handleSignature(sig);
+      printHeapTypeName(o, type);
+      o << ' ';
+      handleHeapType(type);
       o << ")" << maybeNewLine;
     }
     ModuleUtils::iterImportedMemories(
@@ -2669,29 +3095,17 @@
   void run(PassRunner* runner, Module* module) override {
     PrintSExpression print(o);
     print.setDebugInfo(runner->options.debugInfo);
-    print.setPrintStackIR(true);
+    print.setStackIR(true);
     print.visitModule(module);
   }
 };
 
 Pass* createPrintStackIRPass() { return new PrintStackIR(); }
 
-// Print individual expressions
-
-std::ostream& WasmPrinter::printModule(Module* module, std::ostream& o) {
-  PassRunner runner(module);
-  Printer(&o).run(&runner, module);
-  return o;
-}
-
-std::ostream& WasmPrinter::printModule(Module* module) {
-  return printModule(module, std::cout);
-}
-
-std::ostream& WasmPrinter::printExpression(Expression* expression,
-                                           std::ostream& o,
-                                           bool minify,
-                                           bool full) {
+static std::ostream& printExpression(Expression* expression,
+                                     std::ostream& o,
+                                     bool minify,
+                                     bool full) {
   if (!expression) {
     o << "(null expression)";
     return o;
@@ -2706,8 +3120,8 @@
   return o;
 }
 
-std::ostream&
-WasmPrinter::printStackInst(StackInst* inst, std::ostream& o, Function* func) {
+static std::ostream&
+printStackInst(StackInst* inst, std::ostream& o, Function* func) {
   switch (inst->op) {
     case StackInst::Basic: {
       PrintExpressionContents(func, o).visit(inst->origin);
@@ -2741,8 +3155,8 @@
   return o;
 }
 
-std::ostream&
-WasmPrinter::printStackIR(StackIR* ir, std::ostream& o, Function* func) {
+static std::ostream&
+printStackIR(StackIR* ir, std::ostream& o, Function* func) {
   size_t indent = func ? 2 : 0;
   auto doIndent = [&indent, &o]() {
     for (size_t j = 0; j < indent; j++) {
@@ -2806,3 +3220,29 @@
 }
 
 } // namespace wasm
+
+namespace std {
+
+std::ostream& operator<<(std::ostream& o, wasm::Module& module) {
+  wasm::PassRunner runner(&module);
+  wasm::Printer(&o).run(&runner, &module);
+  return o;
+}
+
+std::ostream& operator<<(std::ostream& o, wasm::Expression& expression) {
+  return wasm::printExpression(&expression, o);
+}
+
+std::ostream& operator<<(std::ostream& o, wasm::Expression* expression) {
+  return wasm::printExpression(expression, o);
+}
+
+std::ostream& operator<<(std::ostream& o, wasm::StackInst& inst) {
+  return wasm::printStackInst(&inst, o);
+}
+
+std::ostream& operator<<(std::ostream& o, wasm::StackIR& ir) {
+  return wasm::printStackIR(&ir, o);
+}
+
+} // namespace std
diff --git a/binaryen/src/passes/ReReloop.cpp b/binaryen/src/passes/ReReloop.cpp
--- a/binaryen/src/passes/ReReloop.cpp
+++ b/binaryen/src/passes/ReReloop.cpp
@@ -31,10 +31,6 @@
 #include "wasm-traversal.h"
 #include "wasm.h"
 
-#ifdef RERELOOP_DEBUG
-#include <wasm-printing.h>
-#endif
-
 namespace wasm {
 
 struct ReReloop final : public Pass {
@@ -362,7 +358,7 @@
       }
     }
     // TODO: should this be in the relooper itself?
-    ReFinalize().walk(function->body);
+    ReFinalize().walkFunctionInModule(function, module);
   }
 };
 
diff --git a/binaryen/src/passes/RemoveNonJSOps.cpp b/binaryen/src/passes/RemoveNonJSOps.cpp
--- a/binaryen/src/passes/RemoveNonJSOps.cpp
+++ b/binaryen/src/passes/RemoveNonJSOps.cpp
@@ -299,13 +299,6 @@
         functionCall = WASM_NEAREST_F64;
         break;
 
-      case TruncFloat32:
-        functionCall = WASM_TRUNC_F32;
-        break;
-      case TruncFloat64:
-        functionCall = WASM_TRUNC_F64;
-        break;
-
       case PopcntInt64:
         functionCall = WASM_POPCNT64;
         break;
diff --git a/binaryen/src/passes/RemoveUnusedBrs.cpp b/binaryen/src/passes/RemoveUnusedBrs.cpp
--- a/binaryen/src/passes/RemoveUnusedBrs.cpp
+++ b/binaryen/src/passes/RemoveUnusedBrs.cpp
@@ -930,6 +930,17 @@
             !iff->ifFalse->type.isSingle()) {
           return nullptr;
         }
+        if (iff->condition->type == Type::unreachable) {
+          // An if with an unreachable condition may nonetheless have a type
+          // that is not unreachable,
+          //
+          // (if (result i32) (unreachable) ..)
+          //
+          // Turning such an if into a select would change the type of the
+          // expression, which would require updating types further up. Avoid
+          // that, leaving dead code elimination to that dedicated pass.
+          return nullptr;
+        }
         // This is always helpful for code size, but can be a tradeoff with
         // performance as we run both code paths. So when shrinking we always
         // try to do this, but otherwise must consider more carefully.
@@ -937,20 +948,23 @@
               passOptions, iff->ifTrue, iff->ifFalse)) {
           return nullptr;
         }
-        // Check if side effects allow this.
+        // Check if side effects allow this: we need to execute the two arms
+        // unconditionally, and also to make the condition run last.
         FeatureSet features = getModule()->features;
+        EffectAnalyzer ifTrue(passOptions, features, iff->ifTrue);
+        if (ifTrue.hasSideEffects()) {
+          return nullptr;
+        }
+        EffectAnalyzer ifFalse(passOptions, features, iff->ifFalse);
+        if (ifFalse.hasSideEffects()) {
+          return nullptr;
+        }
         EffectAnalyzer condition(passOptions, features, iff->condition);
-        if (!condition.hasSideEffects()) {
-          EffectAnalyzer ifTrue(passOptions, features, iff->ifTrue);
-          if (!ifTrue.hasSideEffects()) {
-            EffectAnalyzer ifFalse(passOptions, features, iff->ifFalse);
-            if (!ifFalse.hasSideEffects()) {
-              return Builder(*getModule())
-                .makeSelect(iff->condition, iff->ifTrue, iff->ifFalse);
-            }
-          }
+        if (condition.invalidates(ifTrue) || condition.invalidates(ifFalse)) {
+          return nullptr;
         }
-        return nullptr;
+        return Builder(*getModule())
+          .makeSelect(iff->condition, iff->ifTrue, iff->ifFalse);
       }
 
       void visitLocalSet(LocalSet* curr) {
diff --git a/binaryen/src/passes/RemoveUnusedModuleElements.cpp b/binaryen/src/passes/RemoveUnusedModuleElements.cpp
--- a/binaryen/src/passes/RemoveUnusedModuleElements.cpp
+++ b/binaryen/src/passes/RemoveUnusedModuleElements.cpp
@@ -22,7 +22,6 @@
 
 #include <memory>
 
-#include "asm_v_wasm.h"
 #include "ir/module-utils.h"
 #include "ir/utils.h"
 #include "pass.h"
diff --git a/binaryen/src/passes/RemoveUnusedNames.cpp b/binaryen/src/passes/RemoveUnusedNames.cpp
--- a/binaryen/src/passes/RemoveUnusedNames.cpp
+++ b/binaryen/src/passes/RemoveUnusedNames.cpp
@@ -19,12 +19,15 @@
 // merge names when possible (by merging their blocks)
 //
 
+#include <ir/branch-utils.h>
 #include <pass.h>
 #include <wasm.h>
 
 namespace wasm {
 
-struct RemoveUnusedNames : public WalkerPass<PostWalker<RemoveUnusedNames>> {
+struct RemoveUnusedNames
+  : public WalkerPass<PostWalker<RemoveUnusedNames,
+                                 UnifiedExpressionVisitor<RemoveUnusedNames>>> {
   bool isFunctionParallel() override { return true; }
 
   Pass* create() override { return new RemoveUnusedNames; }
@@ -33,17 +36,19 @@
   // a parent block, we know if it was branched to
   std::map<Name, std::set<Expression*>> branchesSeen;
 
-  void visitBreak(Break* curr) { branchesSeen[curr->name].insert(curr); }
-
-  void visitSwitch(Switch* curr) {
-    for (auto name : curr->targets) {
-      branchesSeen[name].insert(curr);
+  void visitExpression(Expression* curr) {
+    if (auto* block = curr->dynCast<Block>()) {
+      visitBlock(block);
+      return;
     }
-    branchesSeen[curr->default_].insert(curr);
+    if (auto* loop = curr->dynCast<Loop>()) {
+      visitLoop(loop);
+      return;
+    }
+    BranchUtils::operateOnScopeNameUses(
+      curr, [&](Name& name) { branchesSeen[name].insert(curr); });
   }
 
-  void visitBrOnExn(BrOnExn* curr) { branchesSeen[curr->name].insert(curr); }
-
   void handleBreakTarget(Name& name) {
     if (name.is()) {
       if (branchesSeen.find(name) == branchesSeen.end()) {
@@ -62,26 +67,7 @@
         // same place as breaking out of us, we just need one name (and block)
         auto& branches = branchesSeen[curr->name];
         for (auto* branch : branches) {
-          if (Break* br = branch->dynCast<Break>()) {
-            if (br->name == curr->name) {
-              br->name = child->name;
-            }
-          } else if (Switch* sw = branch->dynCast<Switch>()) {
-            for (auto& target : sw->targets) {
-              if (target == curr->name) {
-                target = child->name;
-              }
-            }
-            if (sw->default_ == curr->name) {
-              sw->default_ = child->name;
-            }
-          } else if (BrOnExn* br = branch->dynCast<BrOnExn>()) {
-            if (br->name == curr->name) {
-              br->name = child->name;
-            }
-          } else {
-            WASM_UNREACHABLE("unexpected expr type");
-          }
+          BranchUtils::replacePossibleTarget(branch, curr->name, child->name);
         }
         child->finalize(child->type);
         replaceCurrent(child);
diff --git a/binaryen/src/passes/ReplaceStackPointer.cpp b/binaryen/src/passes/ReplaceStackPointer.cpp
deleted file mode 100644
--- a/binaryen/src/passes/ReplaceStackPointer.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.
- */
-
-//
-// Convert llvm's stack pointer usage from from global.get/global.set into
-// cals to external stackSave/stackRestore.
-// This is needed to emscripten SIDE_MODULE code where mutable global imports
-// are not yet permitted by default.
-//
-
-#include "abi/js.h"
-#include "ir/import-utils.h"
-#include "pass.h"
-#include "support/debug.h"
-#include "wasm-emscripten.h"
-
-#define DEBUG_TYPE "replace-stack-pointer"
-
-namespace wasm {
-
-static Name STACK_SAVE("stackSave");
-static Name STACK_RESTORE("stackRestore");
-
-struct ReplaceStackPointer
-  : public WalkerPass<PostWalker<ReplaceStackPointer>> {
-  void visitGlobalGet(GlobalGet* curr) {
-    if (getModule()->getGlobalOrNull(curr->name) == stackPointer) {
-      needStackSave = true;
-      if (!builder) {
-        builder = make_unique<Builder>(*getModule());
-      }
-      replaceCurrent(builder->makeCall(STACK_SAVE, {}, Type::i32));
-    }
-  }
-
-  void visitGlobalSet(GlobalSet* curr) {
-    if (getModule()->getGlobalOrNull(curr->name) == stackPointer) {
-      needStackRestore = true;
-      if (!builder) {
-        builder = make_unique<Builder>(*getModule());
-      }
-      replaceCurrent(
-        builder->makeCall(STACK_RESTORE, {curr->value}, Type::none));
-    }
-  }
-
-  void doWalkModule(Module* module) {
-    stackPointer = getStackPointerGlobal(*module);
-    if (!stackPointer) {
-      BYN_DEBUG(std::cerr << "no stack pointer found\n");
-      return;
-    }
-    BYN_DEBUG(std::cerr << "stack pointer found\n");
-    super::doWalkModule(module);
-    if (needStackSave) {
-      ensureFunctionImport(
-        module, STACK_SAVE, Signature(Type::none, Type::i32));
-    }
-    if (needStackRestore) {
-      ensureFunctionImport(
-        module, STACK_RESTORE, Signature(Type::i32, Type::none));
-    }
-    // Finally remove the stack pointer global itself. This avoids importing
-    // a mutable global.
-    module->removeGlobal(stackPointer->name);
-  }
-
-  void ensureFunctionImport(Module* module, Name name, Signature sig) {
-    ImportInfo info(*module);
-    if (info.getImportedFunction(ENV, name)) {
-      return;
-    }
-    auto import = new Function;
-    import->name = name;
-    import->module = ENV;
-    import->base = name;
-    import->sig = sig;
-    module->addFunction(import);
-  }
-
-private:
-  std::unique_ptr<Builder> builder;
-  Global* stackPointer = nullptr;
-  bool needStackSave = false;
-  bool needStackRestore = false;
-};
-
-Pass* createReplaceStackPointerPass() { return new ReplaceStackPointer; }
-
-} // namespace wasm
diff --git a/binaryen/src/passes/SafeHeap.cpp b/binaryen/src/passes/SafeHeap.cpp
--- a/binaryen/src/passes/SafeHeap.cpp
+++ b/binaryen/src/passes/SafeHeap.cpp
@@ -20,7 +20,6 @@
 // top of sbrk()-addressible memory, and incorrect alignment notation.
 //
 
-#include "asm_v_wasm.h"
 #include "asmjs/shared-constants.h"
 #include "ir/bits.h"
 #include "ir/import-utils.h"
@@ -31,7 +30,6 @@
 
 namespace wasm {
 
-static const Name DYNAMICTOP_PTR_IMPORT("DYNAMICTOP_PTR");
 static const Name GET_SBRK_PTR("emscripten_get_sbrk_ptr");
 static const Name SBRK("sbrk");
 static const Name SEGFAULT_IMPORT("segfault");
@@ -68,6 +66,10 @@
   // If the getSbrkPtr function is implemented in the wasm, we must not
   // instrument that, as it would lead to infinite recursion of it calling
   // SAFE_HEAP_LOAD that calls it and so forth.
+  // As well as the getSbrkPtr function we also avoid instrumenting the
+  // module start function.  This is because this function is used in
+  // shared memory builds to load the passive memory segments, which in
+  // turn means that value of sbrk() is not available.
   Name getSbrkPtr;
 
   bool isFunctionParallel() override { return true; }
@@ -79,7 +81,12 @@
   AccessInstrumenter(Name getSbrkPtr) : getSbrkPtr(getSbrkPtr) {}
 
   void visitLoad(Load* curr) {
-    if (getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
+    // As well as the getSbrkPtr function we also avoid insturmenting the
+    // module start function.  This is because this function is used in
+    // shared memory builds to load the passive memory segments, which in
+    // turn means that value of sbrk() is not available.
+    if (getFunction()->name == getModule()->start ||
+        getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
       return;
     }
     Builder builder(*getModule());
@@ -90,7 +97,8 @@
   }
 
   void visitStore(Store* curr) {
-    if (getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
+    if (getFunction()->name == getModule()->start ||
+        getFunction()->name == getSbrkPtr || curr->type == Type::unreachable) {
       return;
     }
     Builder builder(*getModule());
@@ -119,11 +127,7 @@
   void addImports(Module* module) {
     ImportInfo info(*module);
     auto indexType = module->memory.indexType;
-    // Older emscripten imports env.DYNAMICTOP_PTR.
-    // Newer emscripten imports or exports emscripten_get_sbrk_ptr().
-    if (auto* existing = info.getImportedGlobal(ENV, DYNAMICTOP_PTR_IMPORT)) {
-      dynamicTopPtr = existing->name;
-    } else if (auto* existing = info.getImportedFunction(ENV, GET_SBRK_PTR)) {
+    if (auto* existing = info.getImportedFunction(ENV, GET_SBRK_PTR)) {
       getSbrkPtr = existing->name;
     } else if (auto* existing = module->getExportOrNull(GET_SBRK_PTR)) {
       getSbrkPtr = existing->value;
diff --git a/binaryen/src/passes/SimplifyLocals.cpp b/binaryen/src/passes/SimplifyLocals.cpp
--- a/binaryen/src/passes/SimplifyLocals.cpp
+++ b/binaryen/src/passes/SimplifyLocals.cpp
@@ -964,16 +964,23 @@
               }
               anotherCycle = true;
             }
+            // Nothing more to do, ignore the copy.
+            return;
           } else if (func->getLocalType(curr->index) ==
                      func->getLocalType(get->index)) {
-            // There is a new equivalence now.
+            // There is a new equivalence now. Remove all the old ones, and add
+            // the new one.
+            // Note that we ignore the case of subtyping here, to keep this
+            // optimization simple by assuming all equivalent indexes also have
+            // the same type. TODO: consider optimizing this.
             equivalences.reset(curr->index);
             equivalences.add(curr->index, get->index);
+            return;
           }
-        } else {
-          // A new value is assigned here.
-          equivalences.reset(curr->index);
         }
+        // A new value of some kind is assigned here, and it's not something we
+        // could handle earlier, so remove all the old equivalent ones.
+        equivalences.reset(curr->index);
       }
 
       void visitLocalGet(LocalGet* curr) {
diff --git a/binaryen/src/passes/Souperify.cpp b/binaryen/src/passes/Souperify.cpp
--- a/binaryen/src/passes/Souperify.cpp
+++ b/binaryen/src/passes/Souperify.cpp
@@ -464,8 +464,7 @@
       case Node::Type::Expr: {
         if (debug()) {
           std::cout << "; ";
-          WasmPrinter::printExpression(node->expr, std::cout, true);
-          std::cout << '\n';
+          std::cout << *node->expr << '\n';
         }
         std::cout << "%" << indexing[node] << " = ";
         printExpression(node);
diff --git a/binaryen/src/passes/SpillPointers.cpp b/binaryen/src/passes/SpillPointers.cpp
deleted file mode 100644
--- a/binaryen/src/passes/SpillPointers.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * 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.
- */
-
-//
-// Spills values that might be pointers to the C stack. This allows
-// Boehm-style GC to see them properly.
-//
-// To reduce the overhead of the extra operations added here, you
-// should probably run optimizations after doing it.
-// TODO: add a dead store elimination pass, which would help here
-//
-//  * There is currently no check that there is enough stack space.
-//
-
-#include "abi/abi.h"
-#include "abi/stack.h"
-#include "cfg/liveness-traversal.h"
-#include "pass.h"
-#include "wasm-builder.h"
-#include "wasm.h"
-
-namespace wasm {
-
-struct SpillPointers
-  : public WalkerPass<LivenessWalker<SpillPointers, Visitor<SpillPointers>>> {
-  bool isFunctionParallel() override { return true; }
-
-  Pass* create() override { return new SpillPointers; }
-
-  // a mapping of the pointers to all the spillable things. We need to know
-  // how to replace them, and as we spill we may modify them. This map
-  // gives us, for an Expression** seen during the walk (and placed in the
-  // basic block, which is what we iterate on for efficiency) => the
-  // current actual pointer, which may have moded
-  std::unordered_map<Expression**, Expression**> actualPointers;
-
-  // note calls in basic blocks
-  template<typename T> void visitSpillable(T* curr) {
-    // if in unreachable code, ignore
-    if (!currBasicBlock) {
-      return;
-    }
-    auto* pointer = getCurrentPointer();
-    currBasicBlock->contents.actions.emplace_back(pointer);
-    // starts out as correct, may change later
-    actualPointers[pointer] = pointer;
-  }
-
-  void visitCall(Call* curr) { visitSpillable(curr); }
-  void visitCallIndirect(CallIndirect* curr) { visitSpillable(curr); }
-
-  // main entry point
-
-  void doWalkFunction(Function* func) {
-    if (!canRun(func)) {
-      return;
-    }
-    super::doWalkFunction(func);
-    spillPointers();
-  }
-
-  // map pointers to their offset in the spill area
-  typedef std::unordered_map<Index, Index> PointerMap;
-
-  void spillPointers() {
-    // we only care about possible pointers
-    auto* func = getFunction();
-    PointerMap pointerMap;
-    for (Index i = 0; i < func->getNumLocals(); i++) {
-      if (func->getLocalType(i) == ABI::PointerType) {
-        auto offset = pointerMap.size() * ABI::PointerType.getByteSize();
-        pointerMap[i] = offset;
-      }
-    }
-    // find calls and spill around them
-    bool spilled = false;
-    Index spillLocal = -1;
-    for (auto& curr : basicBlocks) {
-      if (liveBlocks.count(curr.get()) == 0) {
-        continue; // ignore dead blocks
-      }
-      auto& liveness = curr->contents;
-      auto& actions = liveness.actions;
-      Index lastCall = -1;
-      for (Index i = 0; i < actions.size(); i++) {
-        auto& action = liveness.actions[i];
-        if (action.isOther()) {
-          lastCall = i;
-        }
-      }
-      if (lastCall == Index(-1)) {
-        continue; // nothing to see here
-      }
-      // scan through the block, spilling around the calls
-      // TODO: we can filter on pointerMap everywhere
-      SetOfLocals live = liveness.end;
-      for (int i = int(actions.size()) - 1; i >= 0; i--) {
-        auto& action = actions[i];
-        if (action.isGet()) {
-          live.insert(action.index);
-        } else if (action.isSet()) {
-          live.erase(action.index);
-        } else if (action.isOther()) {
-          std::vector<Index> toSpill;
-          for (auto index : live) {
-            if (pointerMap.count(index) > 0) {
-              toSpill.push_back(index);
-            }
-          }
-          if (!toSpill.empty()) {
-            // we now have a call + the information about which locals
-            // should be spilled
-            if (!spilled) {
-              // prepare stack support: get a pointer to stack space big enough
-              // for all our data
-              spillLocal = Builder::addVar(func, ABI::PointerType);
-              spilled = true;
-            }
-            // the origin was seen at walk, but the thing may have moved
-            auto* pointer = actualPointers[action.origin];
-            spillPointersAroundCall(
-              pointer, toSpill, spillLocal, pointerMap, func, getModule());
-          }
-        } else {
-          WASM_UNREACHABLE("unexpected action");
-        }
-      }
-    }
-    if (spilled) {
-      // get the stack space, and set the local to it
-      ABI::getStackSpace(spillLocal,
-                         func,
-                         ABI::PointerType.getByteSize() * pointerMap.size(),
-                         *getModule());
-    }
-  }
-
-  void spillPointersAroundCall(Expression** origin,
-                               std::vector<Index>& toSpill,
-                               Index spillLocal,
-                               PointerMap& pointerMap,
-                               Function* func,
-                               Module* module) {
-    auto* call = *origin;
-    if (call->type == Type::unreachable) {
-      return; // the call is never reached anyhow, ignore
-    }
-    Builder builder(*module);
-    auto* block = builder.makeBlock();
-    // move the operands into locals, as we must spill after they are executed
-    auto handleOperand = [&](Expression*& operand) {
-      auto temp = builder.addVar(func, operand->type);
-      auto* set = builder.makeLocalSet(temp, operand);
-      block->list.push_back(set);
-      block->finalize();
-      if (actualPointers.count(&operand) > 0) {
-        // this is something we track, and it's moving - update
-        actualPointers[&operand] = &set->value;
-      }
-      operand = builder.makeLocalGet(temp, operand->type);
-    };
-    if (call->is<Call>()) {
-      for (auto*& operand : call->cast<Call>()->operands) {
-        handleOperand(operand);
-      }
-    } else if (call->is<CallIndirect>()) {
-      for (auto*& operand : call->cast<CallIndirect>()->operands) {
-        handleOperand(operand);
-      }
-      handleOperand(call->cast<CallIndirect>()->target);
-    } else {
-      WASM_UNREACHABLE("unexpected expr");
-    }
-    // add the spills
-    for (auto index : toSpill) {
-      block->list.push_back(
-        builder.makeStore(ABI::PointerType.getByteSize(),
-                          pointerMap[index],
-                          ABI::PointerType.getByteSize(),
-                          builder.makeLocalGet(spillLocal, ABI::PointerType),
-                          builder.makeLocalGet(index, ABI::PointerType),
-                          ABI::PointerType));
-    }
-    // add the (modified) call
-    block->list.push_back(call);
-    block->finalize();
-    *origin = block;
-  }
-};
-
-Pass* createSpillPointersPass() { return new SpillPointers(); }
-
-} // namespace wasm
diff --git a/binaryen/src/passes/StackCheck.cpp b/binaryen/src/passes/StackCheck.cpp
--- a/binaryen/src/passes/StackCheck.cpp
+++ b/binaryen/src/passes/StackCheck.cpp
@@ -22,6 +22,7 @@
 
 #include "abi/js.h"
 #include "ir/import-utils.h"
+#include "ir/names.h"
 #include "pass.h"
 #include "shared-constants.h"
 #include "support/debug.h"
@@ -31,11 +32,6 @@
 
 namespace wasm {
 
-// The base is where the stack begins. As it goes down, that is the highest
-// valid address.
-static Name STACK_BASE("__stack_base");
-// The limit is the farthest it can grow to, which is the lowest valid address.
-static Name STACK_LIMIT("__stack_limit");
 // Exported function to set the base and the limit.
 static Name SET_STACK_LIMITS("__set_stack_limits");
 
@@ -52,30 +48,18 @@
   }
 }
 
-static void addExportedFunction(Module& module, Function* function) {
-  module.addFunction(function);
-  auto export_ = new Export;
-  export_->name = export_->value = function->name;
-  export_->kind = ExternalKind::Function;
-  module.addExport(export_);
-}
-
-static void generateSetStackLimitFunctions(Module& module) {
-  Builder builder(module);
-  Function* limitsFunc = builder.makeFunction(
-    SET_STACK_LIMITS, Signature({Type::i32, Type::i32}, Type::none), {});
-  LocalGet* getBase = builder.makeLocalGet(0, Type::i32);
-  Expression* storeBase = builder.makeGlobalSet(STACK_BASE, getBase);
-  LocalGet* getLimit = builder.makeLocalGet(1, Type::i32);
-  Expression* storeLimit = builder.makeGlobalSet(STACK_LIMIT, getLimit);
-  limitsFunc->body = builder.makeBlock({storeBase, storeLimit});
-  addExportedFunction(module, limitsFunc);
+static void addExportedFunction(Module& module,
+                                std::unique_ptr<Function> function) {
+  auto export_ =
+    Builder::makeExport(function->name, function->name, ExternalKind::Function);
+  module.addFunction(std::move(function));
+  module.addExport(std::move(export_));
 }
 
 struct EnforceStackLimits : public WalkerPass<PostWalker<EnforceStackLimits>> {
-  EnforceStackLimits(Global* stackPointer,
-                     Global* stackBase,
-                     Global* stackLimit,
+  EnforceStackLimits(const Global* stackPointer,
+                     const Global* stackBase,
+                     const Global* stackLimit,
                      Builder& builder,
                      Name handler)
     : stackPointer(stackPointer), stackBase(stackBase), stackLimit(stackLimit),
@@ -127,9 +111,9 @@
   }
 
 private:
-  Global* stackPointer;
-  Global* stackBase;
-  Global* stackLimit;
+  const Global* stackPointer;
+  const Global* stackBase;
+  const Global* stackLimit;
   Builder& builder;
   Name handler;
 };
@@ -142,6 +126,10 @@
       return;
     }
 
+    // Pick appropriate names.
+    auto stackBaseName = Names::getValidGlobalName(*module, "__stack_base");
+    auto stackLimitName = Names::getValidGlobalName(*module, "__stack_limit");
+
     Name handler;
     auto handlerName =
       runner->options.getArgumentOrDefault("stack-check-handler", "");
@@ -151,22 +139,33 @@
     }
 
     Builder builder(*module);
-    Global* stackBase = builder.makeGlobal(STACK_BASE,
+
+    // Add the globals.
+    auto stackBase =
+      module->addGlobal(builder.makeGlobal(stackBaseName,
                                            stackPointer->type,
                                            builder.makeConst(int32_t(0)),
-                                           Builder::Mutable);
-    module->addGlobal(stackBase);
-
-    Global* stackLimit = builder.makeGlobal(STACK_LIMIT,
-                                            stackPointer->type,
-                                            builder.makeConst(int32_t(0)),
-                                            Builder::Mutable);
-    module->addGlobal(stackLimit);
+                                           Builder::Mutable));
+    auto stackLimit =
+      module->addGlobal(builder.makeGlobal(stackLimitName,
+                                           stackPointer->type,
+                                           builder.makeConst(int32_t(0)),
+                                           Builder::Mutable));
 
+    // Instrument all the code.
     PassRunner innerRunner(module);
     EnforceStackLimits(stackPointer, stackBase, stackLimit, builder, handler)
       .run(&innerRunner, module);
-    generateSetStackLimitFunctions(*module);
+
+    // Generate the exported function.
+    auto limitsFunc = builder.makeFunction(
+      SET_STACK_LIMITS, Signature({Type::i32, Type::i32}, Type::none), {});
+    auto* getBase = builder.makeLocalGet(0, Type::i32);
+    auto* storeBase = builder.makeGlobalSet(stackBaseName, getBase);
+    auto* getLimit = builder.makeLocalGet(1, Type::i32);
+    auto* storeLimit = builder.makeGlobalSet(stackLimitName, getLimit);
+    limitsFunc->body = builder.makeBlock({storeBase, storeLimit});
+    addExportedFunction(*module, std::move(limitsFunc));
   }
 };
 
diff --git a/binaryen/src/passes/TrapMode.cpp b/binaryen/src/passes/TrapMode.cpp
--- a/binaryen/src/passes/TrapMode.cpp
+++ b/binaryen/src/passes/TrapMode.cpp
@@ -20,14 +20,12 @@
 // generates a check and replaces the result with zero in that case.
 //
 
-#include "asm_v_wasm.h"
 #include "asmjs/shared-constants.h"
 #include "ir/trapping.h"
 #include "mixed_arena.h"
 #include "pass.h"
 #include "support/name.h"
 #include "wasm-builder.h"
-#include "wasm-printing.h"
 #include "wasm-type.h"
 #include "wasm.h"
 
@@ -37,6 +35,18 @@
 Name I64U_REM("i64u-rem");
 Name I64S_DIV("i64s-div");
 Name I64U_DIV("i64u-div");
+
+static Expression* ensureDouble(Expression* expr, MixedArena& allocator) {
+  if (expr->type == Type::f32) {
+    auto conv = allocator.alloc<Unary>();
+    conv->op = PromoteFloat32;
+    conv->value = expr;
+    conv->type = Type::f64;
+    return conv;
+  }
+  assert(expr->type == Type::f64);
+  return expr;
+}
 
 Name getBinaryFuncName(Binary* curr) {
   switch (curr->op) {
diff --git a/binaryen/src/passes/Vacuum.cpp b/binaryen/src/passes/Vacuum.cpp
--- a/binaryen/src/passes/Vacuum.cpp
+++ b/binaryen/src/passes/Vacuum.cpp
@@ -20,6 +20,7 @@
 
 #include <ir/block-utils.h>
 #include <ir/effects.h>
+#include <ir/iteration.h>
 #include <ir/literal-utils.h>
 #include <ir/type-updating.h>
 #include <ir/utils.h>
@@ -49,169 +50,85 @@
     walk(func->body);
   }
 
-  // Returns nullptr if curr is dead, curr if it must stay as is, or another
-  // node if it can be replaced. Takes into account:
+  // Returns nullptr if curr is dead, curr if it must stay as is, or one of its
+  // children if it can be replaced. Takes into account:
+  //
   //  * The result may be used or unused.
-  //  * The type may or may not matter (a drop can drop anything, for example).
+  //  * The type may or may not matter.
+  //
+  // For example,
+  //
+  //  (drop
+  //   (i32.eqz
+  //    (call ..)))
+  //
+  // The drop means that the value is not used later. And while the call has
+  // side effects, the i32.eqz does not. So when we are called on the i32.eqz,
+  // and told the result does not matter, we can return the call. Note that in
+  // this case the type does not matter either, as drop doesn't care, and anyhow
+  // i32.eqz returns the same type as it receives. But for an expression that
+  // returns a different type, if the type matters then we cannot replace it.
   Expression* optimize(Expression* curr, bool resultUsed, bool typeMatters) {
     FeatureSet features = getModule()->features;
     auto type = curr->type;
-    // An unreachable node must not be changed.
+    // If the type is none, then we can never replace it with another type.
+    if (type == Type::none) {
+      typeMatters = true;
+    }
+    // An unreachable node must not be changed. DCE will remove those.
     if (type == Type::unreachable) {
       return curr;
     }
-    // We iterate on possible replacements. If a replacement changes the type,
-    // stop and go back.
+    // resultUsed only makes sense when the type is concrete
+    assert(!resultUsed || curr->type != Type::none);
+    // If we actually need the result, then we must not change anything.
+    // TODO: maybe there is something clever though?
+    if (resultUsed) {
+      return curr;
+    }
+    // We iterate on possible replacements.
     auto* prev = curr;
     while (1) {
+      // If a replacement changes the type, and the type matters, return the
+      // previous one and stop.
       if (typeMatters && curr->type != type) {
         return prev;
       }
       prev = curr;
-      switch (curr->_id) {
-        case Expression::Id::NopId:
-          return nullptr; // never needed
-
-        case Expression::Id::BlockId:
-          return curr; // not always needed, but handled in visitBlock()
-        case Expression::Id::IfId:
-          return curr; // not always needed, but handled in visitIf()
-        case Expression::Id::LoopId:
-          return curr; // not always needed, but handled in visitLoop()
-        case Expression::Id::DropId:
-          return curr; // not always needed, but handled in visitDrop()
-        case Expression::Id::TryId:
-          return curr; // not always needed, but handled in visitTry()
-
-        case Expression::Id::BreakId:
-        case Expression::Id::SwitchId:
-        case Expression::Id::BrOnExnId:
-        case Expression::Id::CallId:
-        case Expression::Id::CallIndirectId:
-        case Expression::Id::LocalSetId:
-        case Expression::Id::StoreId:
-        case Expression::Id::ReturnId:
-        case Expression::Id::GlobalSetId:
-        case Expression::Id::MemorySizeId:
-        case Expression::Id::MemoryGrowId:
-        case Expression::Id::UnreachableId:
-          return curr; // always needed
-
-        case Expression::Id::LoadId: {
-          // it is ok to remove a load if the result is not used, and it has no
-          // side effects (the load itself may trap, if we are not ignoring such
-          // things)
-          auto* load = curr->cast<Load>();
-          if (!resultUsed && !EffectAnalyzer(getPassOptions(), features, curr)
-                                .hasSideEffects()) {
-            if (!typeMatters || load->ptr->type == type) {
-              return load->ptr;
-            }
-          }
-          return curr;
-        }
-        case Expression::Id::ConstId:
-        case Expression::Id::LocalGetId:
-        case Expression::Id::GlobalGetId: {
-          if (!resultUsed) {
-            return nullptr;
-          }
-          return curr;
-        }
-
-        case Expression::Id::UnaryId:
-        case Expression::Id::BinaryId:
-        case Expression::Id::SelectId: {
-          if (resultUsed) {
-            return curr; // used, keep it
-          }
-          // for unary, binary, and select, we need to check their arguments for
-          // side effects, as well as the node itself, as some unaries and
-          // binaries have implicit traps
-          if (auto* unary = curr->dynCast<Unary>()) {
-            EffectAnalyzer tester(getPassOptions(), features);
-            tester.visitUnary(unary);
-            if (tester.hasSideEffects()) {
-              return curr;
-            }
-            if (EffectAnalyzer(getPassOptions(), features, unary->value)
-                  .hasSideEffects()) {
-              curr = unary->value;
-              continue;
-            } else {
-              return nullptr;
-            }
-          } else if (auto* binary = curr->dynCast<Binary>()) {
-            EffectAnalyzer tester(getPassOptions(), features);
-            tester.visitBinary(binary);
-            if (tester.hasSideEffects()) {
-              return curr;
-            }
-            if (EffectAnalyzer(getPassOptions(), features, binary->left)
-                  .hasSideEffects()) {
-              if (EffectAnalyzer(getPassOptions(), features, binary->right)
-                    .hasSideEffects()) {
-                return curr; // leave them
-              } else {
-                curr = binary->left;
-                continue;
-              }
-            } else {
-              if (EffectAnalyzer(getPassOptions(), features, binary->right)
-                    .hasSideEffects()) {
-                curr = binary->right;
-                continue;
-              } else {
-                return nullptr;
-              }
-            }
-          } else {
-            // TODO: if two have side effects, we could replace the select with
-            // say an add?
-            auto* select = curr->cast<Select>();
-            if (EffectAnalyzer(getPassOptions(), features, select->ifTrue)
-                  .hasSideEffects()) {
-              if (EffectAnalyzer(getPassOptions(), features, select->ifFalse)
-                    .hasSideEffects()) {
-                return curr; // leave them
-              } else {
-                if (EffectAnalyzer(
-                      getPassOptions(), features, select->condition)
-                      .hasSideEffects()) {
-                  return curr; // leave them
-                } else {
-                  curr = select->ifTrue;
-                  continue;
-                }
-              }
-            } else {
-              if (EffectAnalyzer(getPassOptions(), features, select->ifFalse)
-                    .hasSideEffects()) {
-                if (EffectAnalyzer(
-                      getPassOptions(), features, select->condition)
-                      .hasSideEffects()) {
-                  return curr; // leave them
-                } else {
-                  curr = select->ifFalse;
-                  continue;
-                }
-              } else {
-                if (EffectAnalyzer(
-                      getPassOptions(), features, select->condition)
-                      .hasSideEffects()) {
-                  curr = select->condition;
-                  continue;
-                } else {
-                  return nullptr;
-                }
-              }
-            }
-          }
+      // Some instructions have special handling in visit*, and we should do
+      // nothing for them here.
+      if (curr->is<Drop>() || curr->is<Block>() || curr->is<If>() ||
+          curr->is<Loop>() || curr->is<Try>()) {
+        return curr;
+      }
+      // Check if this expression itself has side effects, ignoring children.
+      EffectAnalyzer self(getPassOptions(), features);
+      self.visit(curr);
+      if (self.hasSideEffects()) {
+        return curr;
+      }
+      // The result isn't used, and this has no side effects itself, so we can
+      // get rid of it. However, the children may have side effects.
+      SmallVector<Expression*, 1> childrenWithEffects;
+      for (auto* child : ChildIterator(curr)) {
+        if (EffectAnalyzer(getPassOptions(), features, child)
+              .hasSideEffects()) {
+          childrenWithEffects.push_back(child);
         }
-
-        default:
-          return curr; // assume needed
       }
+      if (childrenWithEffects.empty()) {
+        return nullptr;
+      }
+      if (childrenWithEffects.size() == 1) {
+        // We know the result isn't used, and curr has no side effects, so we
+        // can skip curr and keep looking into the child.
+        curr = childrenWithEffects[0];
+        continue;
+      }
+      // TODO: with multiple children with side effects, we can perhaps figure
+      // out something clever, like a block with drops, or an i32.add for just
+      // two, etc.
+      return curr;
     }
   }
 
diff --git a/binaryen/src/passes/WasmIntrinsics.cpp b/binaryen/src/passes/WasmIntrinsics.cpp
--- a/binaryen/src/passes/WasmIntrinsics.cpp
+++ b/binaryen/src/passes/WasmIntrinsics.cpp
@@ -2,8 +2,8 @@
 
 #include "passes/intrinsics-module.h"
 
-static const char theModule[24267] = {
-59, 59, 32, 65, 32, 108, 97, 114, 103, 101, 32, 87, 65, 83, 84, 32, 98, 108, 111, 98, 32, 119, 104, 105, 99, 104, 32, 99, 111, 110, 116, 97, 105, 110, 115, 32, 116, 104, 101, 32, 105, 109, 112, 108, 101, 109, 101, 110, 116, 97, 116, 105, 111, 110, 115, 32, 111, 102, 32, 97, 108, 108, 32, 116, 104, 101, 32, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 10, 59, 59, 32, 116, 104, 97, 116, 32, 119, 101, 32, 105, 110, 106, 101, 99, 116, 32, 97, 115, 32, 112, 97, 114, 116, 32, 111, 102, 32, 116, 104, 105, 115, 32, 109, 111, 100, 117, 108, 101, 46, 32, 84, 104, 105, 115, 32, 98, 108, 111, 98, 32, 119, 97, 115, 32, 103, 101, 110, 101, 114, 97, 116, 101, 100, 32, 102, 114, 111, 109, 32, 97, 32, 82, 117, 115, 116, 10, 59, 59, 32, 112, 114, 111, 103, 114, 97, 109, 32, 91, 49, 93, 32, 119, 104, 105, 99, 104, 32, 117, 115, 101, 115, 32, 116, 104, 101, 32, 82, 117, 115, 116, 32, 99, 111, 109, 112, 105, 108, 101, 114, 45, 98, 117, 105, 108, 116, 105, 110, 115, 32, 112, 114, 111, 106, 101, 99, 116, 46, 32, 73, 116, 39, 115, 32, 110, 111, 116, 10, 59, 59, 32, 110, 101, 99, 101, 115, 115, 97, 114, 105, 108, 121, 32, 112, 101, 114, 102, 101, 99, 116, 32, 98, 117, 116, 32, 103, 101, 116, 115, 32, 116, 104, 101, 32, 106, 111, 98, 32, 100, 111, 110, 101, 33, 32, 84, 104, 101, 32, 105, 100, 101, 97, 32, 104, 101, 114, 101, 32, 105, 115, 32, 116, 104, 97, 116, 32, 119, 101, 32, 105, 110, 106, 101, 99, 116, 10, 59, 59, 32, 116, 104, 101, 115, 101, 32, 112, 114, 101, 116, 116, 121, 32, 101, 97, 114, 108, 121, 32, 115, 111, 32, 116, 104, 101, 121, 32, 99, 97, 110, 32, 99, 111, 110, 116, 105, 110, 117, 101, 32, 116, 111, 32, 98, 101, 32, 111, 112, 116, 105, 109, 105, 122, 101, 100, 32, 98, 121, 32, 102, 117, 114, 116, 104, 101, 114, 32, 112, 97, 115, 115, 101, 115, 10, 59, 59, 32, 40, 97, 107, 97, 32, 105, 110, 108, 105, 110, 105, 110, 103, 32, 97, 110, 100, 32, 119, 104, 97, 116, 110, 111, 116, 41, 10, 59, 59, 10, 59, 59, 32, 76, 79, 67, 65, 76, 32, 77, 79, 68, 83, 32, 100, 111, 110, 101, 32, 98, 121, 32, 104, 97, 110, 100, 32, 97, 102, 116, 101, 114, 119, 97, 114, 100, 115, 58, 10, 59, 59, 32, 32, 42, 32, 82, 101, 109, 111, 118, 101, 32, 104, 97, 114, 100, 99, 111, 100, 101, 100, 32, 97, 100, 100, 114, 101, 115, 115, 32, 49, 48, 50, 52, 32, 119, 104, 105, 99, 104, 32, 119, 97, 115, 32, 117, 115, 101, 100, 32, 102, 111, 114, 32, 116, 101, 109, 112, 111, 114, 97, 114, 121, 32, 100, 97, 116, 97, 59, 32, 105, 110, 115, 116, 101, 97, 100, 10, 59, 59, 32, 32, 32, 32, 97, 100, 100, 32, 36, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 32, 103, 108, 111, 98, 97, 108, 32, 102, 111, 114, 32, 116, 104, 97, 116, 46, 10, 59, 59, 32, 32, 42, 32, 70, 105, 120, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 116, 121, 112, 101, 32, 111, 102, 32, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 54, 52, 44, 32, 119, 104, 105, 99, 104, 32, 119, 97, 115, 32, 119, 114, 111, 110, 103, 32, 115, 111, 109, 101, 104, 111, 119, 44, 10, 59, 59, 32, 32, 32, 32, 105, 51, 50, 44, 32, 105, 51, 50, 32, 61, 62, 32, 105, 51, 50, 32, 105, 110, 115, 116, 101, 97, 100, 32, 111, 102, 32, 105, 54, 52, 32, 61, 62, 32, 105, 54, 52, 10, 59, 59, 32, 32, 42, 32, 82, 101, 109, 111, 118, 101, 32, 117, 110, 110, 101, 99, 101, 115, 115, 97, 114, 121, 32, 109, 101, 109, 111, 114, 121, 32, 105, 109, 112, 111, 114, 116, 46, 10, 59, 59, 10, 59, 59, 32, 91, 49, 93, 58, 32, 104, 116, 116, 112, 115, 58, 47, 47, 103, 105, 115, 116, 46, 103, 105, 116, 104, 117, 98, 46, 99, 111, 109, 47, 97, 108, 101, 120, 99, 114, 105, 99, 104, 116, 111, 110, 47, 101, 55, 101, 97, 54, 55, 98, 99, 100, 100, 49, 55, 99, 101, 52, 98, 54, 50, 53, 52, 101, 54, 54, 102, 55, 55, 49, 54, 53, 54, 57, 48, 10, 10, 40, 109, 111, 100, 117, 108, 101, 10, 32, 40, 116, 121, 112, 101, 32, 36, 48, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 105, 54, 52, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 49, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 102, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 51, 50, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 50, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 102, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 54, 52, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 51, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 52, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 105, 51, 50, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 53, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 100, 105, 118, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 100, 105, 118, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 100, 105, 118, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 100, 105, 118, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 114, 101, 109, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 114, 101, 109, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 114, 101, 109, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 114, 101, 109, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 109, 117, 108, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 109, 117, 108, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 116, 114, 117, 110, 99, 95, 102, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 116, 114, 117, 110, 99, 95, 102, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 116, 114, 117, 110, 99, 95, 102, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 116, 114, 117, 110, 99, 95, 102, 54, 52, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 54, 52, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 54, 52, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 54, 52, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 54, 52, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 54, 52, 41, 41, 10, 32, 40, 103, 108, 111, 98, 97, 108, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 32, 40, 109, 117, 116, 32, 105, 54, 52, 41, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 41, 10, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 51, 50, 46, 112, 111, 112, 99, 110, 116, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 99, 111, 117, 110, 116, 115, 32, 116, 104, 101, 32, 110, 117, 109, 98, 101, 114, 32, 111, 102, 32, 98, 105, 116, 115, 32, 115, 101, 116, 32, 105, 110, 32, 116, 104, 101, 10, 32, 59, 59, 32, 105, 110, 112, 117, 116, 32, 97, 110, 100, 32, 114, 101, 116, 117, 114, 110, 115, 32, 116, 104, 101, 32, 114, 101, 115, 117, 108, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 51, 50, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 49, 32, 105, 51, 50, 41, 10, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 32, 40, 108, 111, 111, 112, 32, 36, 108, 97, 98, 101, 108, 36, 50, 10, 32, 32, 32, 32, 40, 100, 114, 111, 112, 10, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 112, 111, 112, 99, 110, 116, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 99, 111, 117, 110, 116, 115, 32, 116, 104, 101, 32, 110, 117, 109, 98, 101, 114, 32, 111, 102, 32, 98, 105, 116, 115, 32, 115, 101, 116, 32, 105, 110, 32, 116, 104, 101, 10, 32, 59, 59, 32, 105, 110, 112, 117, 116, 32, 97, 110, 100, 32, 114, 101, 116, 117, 114, 110, 115, 32, 116, 104, 101, 32, 114, 101, 115, 117, 108, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 54, 52, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 10, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 32, 40, 108, 111, 111, 112, 32, 36, 108, 97, 98, 101, 108, 36, 50, 10, 32, 32, 32, 32, 40, 100, 114, 111, 112, 10, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 100, 105, 118, 95, 115, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 47, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 100, 105, 118, 32, 40, 59, 32, 48, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 115, 100, 105, 118, 51, 68, 105, 118, 51, 100, 105, 118, 49, 55, 104, 101, 55, 56, 102, 99, 52, 56, 51, 101, 52, 49, 100, 55, 101, 99, 55, 69, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 100, 105, 118, 95, 117, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 47, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 100, 105, 118, 32, 40, 59, 32, 49, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 117, 100, 105, 118, 49, 48, 100, 105, 118, 109, 111, 100, 95, 117, 54, 52, 49, 55, 104, 54, 48, 50, 54, 57, 49, 48, 98, 53, 101, 100, 48, 56, 101, 52, 48, 69, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 114, 101, 109, 95, 115, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 37, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 114, 101, 109, 32, 40, 59, 32, 50, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 115, 100, 105, 118, 51, 77, 111, 100, 52, 109, 111, 100, 95, 49, 55, 104, 50, 99, 98, 98, 55, 98, 98, 102, 51, 54, 101, 52, 49, 100, 54, 56, 69, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 114, 101, 109, 95, 117, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 37, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 114, 101, 109, 32, 40, 59, 32, 51, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 100, 114, 111, 112, 10, 32, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 117, 100, 105, 118, 49, 48, 100, 105, 118, 109, 111, 100, 95, 117, 54, 52, 49, 55, 104, 54, 48, 50, 54, 57, 49, 48, 98, 53, 101, 100, 48, 56, 101, 52, 48, 69, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 103, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 109, 117, 108, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 42, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 109, 117, 108, 32, 40, 59, 32, 52, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 51, 109, 117, 108, 51, 77, 117, 108, 51, 109, 117, 108, 49, 55, 104, 48, 55, 48, 101, 57, 97, 49, 99, 54, 57, 102, 97, 101, 99, 53, 98, 69, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 102, 51, 50, 46, 116, 114, 117, 110, 99, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 117, 110, 100, 115, 32, 116, 111, 32, 116, 104, 101, 32, 110, 101, 97, 114, 101, 115, 116, 32, 105, 110, 116, 101, 103, 101, 114, 44, 10, 32, 59, 59, 32, 116, 111, 119, 97, 114, 100, 115, 32, 122, 101, 114, 111, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 116, 114, 117, 110, 99, 95, 102, 51, 50, 32, 40, 59, 32, 53, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 49, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 102, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 51, 50, 41, 10, 32, 32, 40, 115, 101, 108, 101, 99, 116, 10, 32, 32, 32, 40, 102, 51, 50, 46, 99, 101, 105, 108, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 102, 51, 50, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 102, 51, 50, 46, 108, 116, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 102, 54, 52, 46, 116, 114, 117, 110, 99, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 117, 110, 100, 115, 32, 116, 111, 32, 116, 104, 101, 32, 110, 101, 97, 114, 101, 115, 116, 32, 105, 110, 116, 101, 103, 101, 114, 44, 10, 32, 59, 59, 32, 116, 111, 119, 97, 114, 100, 115, 32, 122, 101, 114, 111, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 116, 114, 117, 110, 99, 95, 102, 54, 52, 32, 40, 59, 32, 54, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 50, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 102, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 54, 52, 41, 10, 32, 32, 40, 115, 101, 108, 101, 99, 116, 10, 32, 32, 32, 40, 102, 54, 52, 46, 99, 101, 105, 108, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 102, 54, 52, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 102, 54, 52, 46, 108, 116, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 51, 50, 46, 99, 116, 122, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 99, 111, 117, 110, 116, 105, 110, 103, 32, 116, 104, 101, 32, 110, 117, 109, 98, 101, 114, 32, 111, 102, 32, 122, 101, 114, 111, 115, 32, 105, 110, 32, 36, 118, 97, 114, 36, 48, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 51, 50, 32, 40, 59, 32, 55, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 51, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 40, 105, 102, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 99, 116, 122, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 99, 111, 117, 110, 116, 105, 110, 103, 32, 116, 104, 101, 32, 110, 117, 109, 98, 101, 114, 32, 111, 102, 32, 122, 101, 114, 111, 115, 32, 105, 110, 32, 36, 118, 97, 114, 36, 48, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 54, 52, 32, 40, 59, 32, 56, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 53, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 102, 10, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 52, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 51, 50, 46, 114, 111, 116, 108, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 116, 97, 116, 105, 110, 103, 32, 116, 104, 101, 32, 102, 105, 114, 115, 116, 32, 97, 114, 103, 117, 109, 101, 110, 116, 44, 32, 119, 105, 116, 104, 10, 32, 59, 59, 32, 119, 114, 97, 112, 97, 114, 111, 117, 110, 100, 44, 32, 98, 121, 32, 116, 104, 101, 32, 115, 101, 99, 111, 110, 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 51, 50, 32, 40, 59, 32, 56, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 51, 50, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 51, 50, 41, 10, 32, 32, 40, 105, 51, 50, 46, 111, 114, 10, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 51, 50, 46, 114, 111, 116, 114, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 116, 97, 116, 105, 110, 103, 32, 116, 104, 101, 32, 102, 105, 114, 115, 116, 32, 97, 114, 103, 117, 109, 101, 110, 116, 44, 32, 119, 105, 116, 104, 10, 32, 59, 59, 32, 119, 114, 97, 112, 97, 114, 111, 117, 110, 100, 44, 32, 98, 121, 32, 116, 104, 101, 32, 115, 101, 99, 111, 110, 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 51, 50, 32, 40, 59, 32, 57, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 51, 50, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 51, 50, 41, 10, 32, 32, 40, 105, 51, 50, 46, 111, 114, 10, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 114, 111, 116, 108, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 116, 97, 116, 105, 110, 103, 32, 116, 104, 101, 32, 102, 105, 114, 115, 116, 32, 97, 114, 103, 117, 109, 101, 110, 116, 44, 32, 119, 105, 116, 104, 10, 32, 59, 59, 32, 119, 114, 97, 112, 97, 114, 111, 117, 110, 100, 44, 32, 98, 121, 32, 116, 104, 101, 32, 115, 101, 99, 111, 110, 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 54, 52, 32, 40, 59, 32, 49, 48, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 114, 111, 116, 114, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 116, 97, 116, 105, 110, 103, 32, 116, 104, 101, 32, 102, 105, 114, 115, 116, 32, 97, 114, 103, 117, 109, 101, 110, 116, 44, 32, 119, 105, 116, 104, 10, 32, 59, 59, 32, 119, 114, 97, 112, 97, 114, 111, 117, 110, 100, 44, 32, 98, 121, 32, 116, 104, 101, 32, 115, 101, 99, 111, 110, 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 54, 52, 32, 40, 59, 32, 49, 49, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 102, 51, 50, 46, 110, 101, 97, 114, 101, 115, 116, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 117, 110, 100, 105, 110, 103, 32, 116, 104, 101, 32, 105, 110, 112, 117, 116, 32, 116, 111, 32, 116, 104, 101, 32, 110, 101, 97, 114, 101, 115, 116, 10, 32, 59, 59, 32, 105, 110, 116, 101, 103, 101, 114, 32, 119, 104, 105, 108, 101, 32, 98, 114, 101, 97, 107, 105, 110, 103, 32, 116, 105, 101, 115, 32, 98, 121, 32, 114, 111, 117, 110, 100, 105, 110, 103, 32, 116, 111, 32, 101, 118, 101, 110, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 51, 50, 32, 40, 59, 32, 49, 50, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 49, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 102, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 49, 32, 102, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 102, 51, 50, 41, 10, 32, 32, 40, 105, 102, 10, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 40, 102, 51, 50, 46, 108, 116, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 98, 108, 111, 99, 107, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 101, 105, 108, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 105, 102, 10, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 103, 116, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 40, 115, 101, 108, 101, 99, 116, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 101, 113, 10, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 102, 54, 52, 46, 110, 101, 97, 114, 101, 115, 116, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 117, 110, 100, 105, 110, 103, 32, 116, 104, 101, 32, 105, 110, 112, 117, 116, 32, 116, 111, 32, 116, 104, 101, 32, 110, 101, 97, 114, 101, 115, 116, 10, 32, 59, 59, 32, 105, 110, 116, 101, 103, 101, 114, 32, 119, 104, 105, 108, 101, 32, 98, 114, 101, 97, 107, 105, 110, 103, 32, 116, 105, 101, 115, 32, 98, 121, 32, 114, 111, 117, 110, 100, 105, 110, 103, 32, 116, 111, 32, 101, 118, 101, 110, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 54, 52, 32, 40, 59, 32, 49, 51, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 50, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 102, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 49, 32, 102, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 102, 54, 52, 41, 10, 32, 32, 40, 105, 102, 10, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 40, 102, 54, 52, 46, 108, 116, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 98, 108, 111, 99, 107, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 101, 105, 108, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 105, 102, 10, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 103, 116, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 40, 115, 101, 108, 101, 99, 116, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 101, 113, 10, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 41, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 117, 100, 105, 118, 49, 48, 100, 105, 118, 109, 111, 100, 95, 117, 54, 52, 49, 55, 104, 54, 48, 50, 54, 57, 49, 48, 98, 53, 101, 100, 48, 56, 101, 52, 48, 69, 32, 40, 59, 32, 49, 52, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 51, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 52, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 53, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 54, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 55, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 56, 32, 105, 54, 52, 41, 10, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 10, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 50, 10, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 51, 10, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 52, 10, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 57, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 102, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 57, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 108, 101, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 103, 101, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 52, 50, 57, 52, 57, 54, 55, 50, 57, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 100, 105, 118, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 52, 50, 57, 52, 57, 54, 55, 50, 57, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 116, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 100, 105, 118, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 108, 116, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 116, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 53, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 51, 10, 32, 32, 32, 32, 32, 40, 105, 102, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 111, 112, 32, 36, 108, 97, 98, 101, 108, 36, 49, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 56, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 55, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 49, 51, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 53, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 54, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 41, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 51, 109, 117, 108, 51, 77, 117, 108, 51, 109, 117, 108, 49, 55, 104, 48, 55, 48, 101, 57, 97, 49, 99, 54, 57, 102, 97, 101, 99, 53, 98, 69, 32, 40, 59, 32, 49, 53, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 51, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 52, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 53, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 54, 32, 105, 51, 50, 41, 10, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 53, 53, 51, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 53, 53, 51, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 53, 53, 51, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 111, 114, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 54, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 53, 53, 51, 53, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 115, 100, 105, 118, 51, 68, 105, 118, 51, 100, 105, 118, 49, 55, 104, 101, 55, 56, 102, 99, 52, 56, 51, 101, 52, 49, 100, 55, 101, 99, 55, 69, 32, 40, 59, 32, 49, 54, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 100, 105, 118, 95, 117, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 115, 100, 105, 118, 51, 77, 111, 100, 52, 109, 111, 100, 95, 49, 55, 104, 50, 99, 98, 98, 55, 98, 98, 102, 51, 54, 101, 52, 49, 100, 54, 56, 69, 32, 40, 59, 32, 49, 55, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 114, 101, 109, 95, 117, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 99, 117, 115, 116, 111, 109, 32, 115, 101, 99, 116, 105, 111, 110, 32, 34, 108, 105, 110, 107, 105, 110, 103, 34, 44, 32, 115, 105, 122, 101, 32, 51, 10, 41, 10, 0
+static const char theModule[23513] = {
+59, 59, 32, 65, 32, 108, 97, 114, 103, 101, 32, 87, 65, 83, 84, 32, 98, 108, 111, 98, 32, 119, 104, 105, 99, 104, 32, 99, 111, 110, 116, 97, 105, 110, 115, 32, 116, 104, 101, 32, 105, 109, 112, 108, 101, 109, 101, 110, 116, 97, 116, 105, 111, 110, 115, 32, 111, 102, 32, 97, 108, 108, 32, 116, 104, 101, 32, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 10, 59, 59, 32, 116, 104, 97, 116, 32, 119, 101, 32, 105, 110, 106, 101, 99, 116, 32, 97, 115, 32, 112, 97, 114, 116, 32, 111, 102, 32, 116, 104, 105, 115, 32, 109, 111, 100, 117, 108, 101, 46, 32, 84, 104, 105, 115, 32, 98, 108, 111, 98, 32, 119, 97, 115, 32, 103, 101, 110, 101, 114, 97, 116, 101, 100, 32, 102, 114, 111, 109, 32, 97, 32, 82, 117, 115, 116, 10, 59, 59, 32, 112, 114, 111, 103, 114, 97, 109, 32, 91, 49, 93, 32, 119, 104, 105, 99, 104, 32, 117, 115, 101, 115, 32, 116, 104, 101, 32, 82, 117, 115, 116, 32, 99, 111, 109, 112, 105, 108, 101, 114, 45, 98, 117, 105, 108, 116, 105, 110, 115, 32, 112, 114, 111, 106, 101, 99, 116, 46, 32, 73, 116, 39, 115, 32, 110, 111, 116, 10, 59, 59, 32, 110, 101, 99, 101, 115, 115, 97, 114, 105, 108, 121, 32, 112, 101, 114, 102, 101, 99, 116, 32, 98, 117, 116, 32, 103, 101, 116, 115, 32, 116, 104, 101, 32, 106, 111, 98, 32, 100, 111, 110, 101, 33, 32, 84, 104, 101, 32, 105, 100, 101, 97, 32, 104, 101, 114, 101, 32, 105, 115, 32, 116, 104, 97, 116, 32, 119, 101, 32, 105, 110, 106, 101, 99, 116, 10, 59, 59, 32, 116, 104, 101, 115, 101, 32, 112, 114, 101, 116, 116, 121, 32, 101, 97, 114, 108, 121, 32, 115, 111, 32, 116, 104, 101, 121, 32, 99, 97, 110, 32, 99, 111, 110, 116, 105, 110, 117, 101, 32, 116, 111, 32, 98, 101, 32, 111, 112, 116, 105, 109, 105, 122, 101, 100, 32, 98, 121, 32, 102, 117, 114, 116, 104, 101, 114, 32, 112, 97, 115, 115, 101, 115, 10, 59, 59, 32, 40, 97, 107, 97, 32, 105, 110, 108, 105, 110, 105, 110, 103, 32, 97, 110, 100, 32, 119, 104, 97, 116, 110, 111, 116, 41, 10, 59, 59, 10, 59, 59, 32, 76, 79, 67, 65, 76, 32, 77, 79, 68, 83, 32, 100, 111, 110, 101, 32, 98, 121, 32, 104, 97, 110, 100, 32, 97, 102, 116, 101, 114, 119, 97, 114, 100, 115, 58, 10, 59, 59, 32, 32, 42, 32, 82, 101, 109, 111, 118, 101, 32, 104, 97, 114, 100, 99, 111, 100, 101, 100, 32, 97, 100, 100, 114, 101, 115, 115, 32, 49, 48, 50, 52, 32, 119, 104, 105, 99, 104, 32, 119, 97, 115, 32, 117, 115, 101, 100, 32, 102, 111, 114, 32, 116, 101, 109, 112, 111, 114, 97, 114, 121, 32, 100, 97, 116, 97, 59, 32, 105, 110, 115, 116, 101, 97, 100, 10, 59, 59, 32, 32, 32, 32, 97, 100, 100, 32, 36, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 32, 103, 108, 111, 98, 97, 108, 32, 102, 111, 114, 32, 116, 104, 97, 116, 46, 10, 59, 59, 32, 32, 42, 32, 70, 105, 120, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 116, 121, 112, 101, 32, 111, 102, 32, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 54, 52, 44, 32, 119, 104, 105, 99, 104, 32, 119, 97, 115, 32, 119, 114, 111, 110, 103, 32, 115, 111, 109, 101, 104, 111, 119, 44, 10, 59, 59, 32, 32, 32, 32, 105, 51, 50, 44, 32, 105, 51, 50, 32, 61, 62, 32, 105, 51, 50, 32, 105, 110, 115, 116, 101, 97, 100, 32, 111, 102, 32, 105, 54, 52, 32, 61, 62, 32, 105, 54, 52, 10, 59, 59, 32, 32, 42, 32, 82, 101, 109, 111, 118, 101, 32, 117, 110, 110, 101, 99, 101, 115, 115, 97, 114, 121, 32, 109, 101, 109, 111, 114, 121, 32, 105, 109, 112, 111, 114, 116, 46, 10, 59, 59, 10, 59, 59, 32, 91, 49, 93, 58, 32, 104, 116, 116, 112, 115, 58, 47, 47, 103, 105, 115, 116, 46, 103, 105, 116, 104, 117, 98, 46, 99, 111, 109, 47, 97, 108, 101, 120, 99, 114, 105, 99, 104, 116, 111, 110, 47, 101, 55, 101, 97, 54, 55, 98, 99, 100, 100, 49, 55, 99, 101, 52, 98, 54, 50, 53, 52, 101, 54, 54, 102, 55, 55, 49, 54, 53, 54, 57, 48, 10, 10, 40, 109, 111, 100, 117, 108, 101, 10, 32, 40, 116, 121, 112, 101, 32, 36, 48, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 105, 54, 52, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 49, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 102, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 51, 50, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 50, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 102, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 54, 52, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 51, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 52, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 105, 51, 50, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 41, 41, 10, 32, 40, 116, 121, 112, 101, 32, 36, 53, 32, 40, 102, 117, 110, 99, 32, 40, 112, 97, 114, 97, 109, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 100, 105, 118, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 100, 105, 118, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 100, 105, 118, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 100, 105, 118, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 114, 101, 109, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 114, 101, 109, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 114, 101, 109, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 114, 101, 109, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 109, 117, 108, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 109, 117, 108, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 54, 52, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 54, 52, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 54, 52, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 54, 52, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 51, 50, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 51, 50, 41, 41, 10, 32, 40, 101, 120, 112, 111, 114, 116, 32, 34, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 54, 52, 34, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 54, 52, 41, 41, 10, 32, 40, 103, 108, 111, 98, 97, 108, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 32, 40, 109, 117, 116, 32, 105, 54, 52, 41, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 41, 10, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 51, 50, 46, 112, 111, 112, 99, 110, 116, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 99, 111, 117, 110, 116, 115, 32, 116, 104, 101, 32, 110, 117, 109, 98, 101, 114, 32, 111, 102, 32, 98, 105, 116, 115, 32, 115, 101, 116, 32, 105, 110, 32, 116, 104, 101, 10, 32, 59, 59, 32, 105, 110, 112, 117, 116, 32, 97, 110, 100, 32, 114, 101, 116, 117, 114, 110, 115, 32, 116, 104, 101, 32, 114, 101, 115, 117, 108, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 51, 50, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 49, 32, 105, 51, 50, 41, 10, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 32, 40, 108, 111, 111, 112, 32, 36, 108, 97, 98, 101, 108, 36, 50, 10, 32, 32, 32, 32, 40, 100, 114, 111, 112, 10, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 112, 111, 112, 99, 110, 116, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 99, 111, 117, 110, 116, 115, 32, 116, 104, 101, 32, 110, 117, 109, 98, 101, 114, 32, 111, 102, 32, 98, 105, 116, 115, 32, 115, 101, 116, 32, 105, 110, 32, 116, 104, 101, 10, 32, 59, 59, 32, 105, 110, 112, 117, 116, 32, 97, 110, 100, 32, 114, 101, 116, 117, 114, 110, 115, 32, 116, 104, 101, 32, 114, 101, 115, 117, 108, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 112, 111, 112, 99, 110, 116, 95, 105, 54, 52, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 10, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 32, 40, 108, 111, 111, 112, 32, 36, 108, 97, 98, 101, 108, 36, 50, 10, 32, 32, 32, 32, 40, 100, 114, 111, 112, 10, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 100, 105, 118, 95, 115, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 47, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 100, 105, 118, 32, 40, 59, 32, 48, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 115, 100, 105, 118, 51, 68, 105, 118, 51, 100, 105, 118, 49, 55, 104, 101, 55, 56, 102, 99, 52, 56, 51, 101, 52, 49, 100, 55, 101, 99, 55, 69, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 100, 105, 118, 95, 117, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 47, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 100, 105, 118, 32, 40, 59, 32, 49, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 117, 100, 105, 118, 49, 48, 100, 105, 118, 109, 111, 100, 95, 117, 54, 52, 49, 55, 104, 54, 48, 50, 54, 57, 49, 48, 98, 53, 101, 100, 48, 56, 101, 52, 48, 69, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 114, 101, 109, 95, 115, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 37, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 115, 114, 101, 109, 32, 40, 59, 32, 50, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 115, 100, 105, 118, 51, 77, 111, 100, 52, 109, 111, 100, 95, 49, 55, 104, 50, 99, 98, 98, 55, 98, 98, 102, 51, 54, 101, 52, 49, 100, 54, 56, 69, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 114, 101, 109, 95, 117, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 37, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 117, 114, 101, 109, 32, 40, 59, 32, 51, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 100, 114, 111, 112, 10, 32, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 117, 100, 105, 118, 49, 48, 100, 105, 118, 109, 111, 100, 95, 117, 54, 52, 49, 55, 104, 54, 48, 50, 54, 57, 49, 48, 98, 53, 101, 100, 48, 56, 101, 52, 48, 69, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 103, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 109, 117, 108, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 101, 116, 117, 114, 110, 32, 36, 118, 97, 114, 48, 32, 42, 32, 36, 118, 97, 114, 36, 49, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 105, 54, 52, 95, 109, 117, 108, 32, 40, 59, 32, 52, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 99, 97, 108, 108, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 51, 109, 117, 108, 51, 77, 117, 108, 51, 109, 117, 108, 49, 55, 104, 48, 55, 48, 101, 57, 97, 49, 99, 54, 57, 102, 97, 101, 99, 53, 98, 69, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 51, 50, 46, 99, 116, 122, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 99, 111, 117, 110, 116, 105, 110, 103, 32, 116, 104, 101, 32, 110, 117, 109, 98, 101, 114, 32, 111, 102, 32, 122, 101, 114, 111, 115, 32, 105, 110, 32, 36, 118, 97, 114, 36, 48, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 51, 50, 32, 40, 59, 32, 55, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 51, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 40, 105, 102, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 99, 116, 122, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 99, 111, 117, 110, 116, 105, 110, 103, 32, 116, 104, 101, 32, 110, 117, 109, 98, 101, 114, 32, 111, 102, 32, 122, 101, 114, 111, 115, 32, 105, 110, 32, 36, 118, 97, 114, 36, 48, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 99, 116, 122, 95, 105, 54, 52, 32, 40, 59, 32, 56, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 53, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 102, 10, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 52, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 51, 50, 46, 114, 111, 116, 108, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 116, 97, 116, 105, 110, 103, 32, 116, 104, 101, 32, 102, 105, 114, 115, 116, 32, 97, 114, 103, 117, 109, 101, 110, 116, 44, 32, 119, 105, 116, 104, 10, 32, 59, 59, 32, 119, 114, 97, 112, 97, 114, 111, 117, 110, 100, 44, 32, 98, 121, 32, 116, 104, 101, 32, 115, 101, 99, 111, 110, 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 51, 50, 32, 40, 59, 32, 56, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 51, 50, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 51, 50, 41, 10, 32, 32, 40, 105, 51, 50, 46, 111, 114, 10, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 51, 50, 46, 114, 111, 116, 114, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 116, 97, 116, 105, 110, 103, 32, 116, 104, 101, 32, 102, 105, 114, 115, 116, 32, 97, 114, 103, 117, 109, 101, 110, 116, 44, 32, 119, 105, 116, 104, 10, 32, 59, 59, 32, 119, 114, 97, 112, 97, 114, 111, 117, 110, 100, 44, 32, 98, 121, 32, 116, 104, 101, 32, 115, 101, 99, 111, 110, 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 51, 50, 32, 40, 59, 32, 57, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 51, 50, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 51, 50, 41, 10, 32, 32, 40, 105, 51, 50, 46, 111, 114, 10, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 114, 111, 116, 108, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 116, 97, 116, 105, 110, 103, 32, 116, 104, 101, 32, 102, 105, 114, 115, 116, 32, 97, 114, 103, 117, 109, 101, 110, 116, 44, 32, 119, 105, 116, 104, 10, 32, 59, 59, 32, 119, 114, 97, 112, 97, 114, 111, 117, 110, 100, 44, 32, 98, 121, 32, 116, 104, 101, 32, 115, 101, 99, 111, 110, 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 108, 95, 105, 54, 52, 32, 40, 59, 32, 49, 48, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 105, 54, 52, 46, 114, 111, 116, 114, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 116, 97, 116, 105, 110, 103, 32, 116, 104, 101, 32, 102, 105, 114, 115, 116, 32, 97, 114, 103, 117, 109, 101, 110, 116, 44, 32, 119, 105, 116, 104, 10, 32, 59, 59, 32, 119, 114, 97, 112, 97, 114, 111, 117, 110, 100, 44, 32, 98, 121, 32, 116, 104, 101, 32, 115, 101, 99, 111, 110, 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 114, 111, 116, 114, 95, 105, 54, 52, 32, 40, 59, 32, 49, 49, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 102, 51, 50, 46, 110, 101, 97, 114, 101, 115, 116, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 117, 110, 100, 105, 110, 103, 32, 116, 104, 101, 32, 105, 110, 112, 117, 116, 32, 116, 111, 32, 116, 104, 101, 32, 110, 101, 97, 114, 101, 115, 116, 10, 32, 59, 59, 32, 105, 110, 116, 101, 103, 101, 114, 32, 119, 104, 105, 108, 101, 32, 98, 114, 101, 97, 107, 105, 110, 103, 32, 116, 105, 101, 115, 32, 98, 121, 32, 114, 111, 117, 110, 100, 105, 110, 103, 32, 116, 111, 32, 101, 118, 101, 110, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 51, 50, 32, 40, 59, 32, 49, 50, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 49, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 102, 51, 50, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 49, 32, 102, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 102, 51, 50, 41, 10, 32, 32, 40, 105, 102, 10, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 40, 102, 51, 50, 46, 108, 116, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 98, 108, 111, 99, 107, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 101, 105, 108, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 105, 102, 10, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 103, 116, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 40, 115, 101, 108, 101, 99, 116, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 101, 113, 10, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 102, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 41, 10, 32, 59, 59, 32, 108, 111, 119, 101, 114, 105, 110, 103, 32, 111, 102, 32, 116, 104, 101, 32, 102, 54, 52, 46, 110, 101, 97, 114, 101, 115, 116, 32, 105, 110, 115, 116, 114, 117, 99, 116, 105, 111, 110, 44, 32, 114, 111, 117, 110, 100, 105, 110, 103, 32, 116, 104, 101, 32, 105, 110, 112, 117, 116, 32, 116, 111, 32, 116, 104, 101, 32, 110, 101, 97, 114, 101, 115, 116, 10, 32, 59, 59, 32, 105, 110, 116, 101, 103, 101, 114, 32, 119, 104, 105, 108, 101, 32, 98, 114, 101, 97, 107, 105, 110, 103, 32, 116, 105, 101, 115, 32, 98, 121, 32, 114, 111, 117, 110, 100, 105, 110, 103, 32, 116, 111, 32, 101, 118, 101, 110, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 95, 119, 97, 115, 109, 95, 110, 101, 97, 114, 101, 115, 116, 95, 102, 54, 52, 32, 40, 59, 32, 49, 51, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 50, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 102, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 102, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 49, 32, 102, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 102, 54, 52, 41, 10, 32, 32, 40, 105, 102, 10, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 40, 102, 54, 52, 46, 108, 116, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 98, 108, 111, 99, 107, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 101, 105, 108, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 105, 102, 10, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 103, 116, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 49, 10, 32, 32, 32, 32, 32, 40, 115, 101, 108, 101, 99, 116, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 101, 113, 10, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 46, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 102, 108, 111, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 102, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 41, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 117, 100, 105, 118, 49, 48, 100, 105, 118, 109, 111, 100, 95, 117, 54, 52, 49, 55, 104, 54, 48, 50, 54, 57, 49, 48, 98, 53, 101, 100, 48, 56, 101, 52, 48, 69, 32, 40, 59, 32, 49, 52, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 51, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 52, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 53, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 54, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 55, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 56, 32, 105, 54, 52, 41, 10, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 10, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 50, 10, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 51, 10, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 52, 10, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 57, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 102, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 57, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 108, 101, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 103, 101, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 52, 50, 57, 52, 57, 54, 55, 50, 57, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 100, 105, 118, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 52, 50, 57, 52, 57, 54, 55, 50, 57, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 116, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 100, 105, 118, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 108, 116, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 108, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 51, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 101, 113, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 116, 122, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 53, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 32, 36, 108, 97, 98, 101, 108, 36, 49, 51, 10, 32, 32, 32, 32, 32, 40, 105, 102, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 40, 98, 108, 111, 99, 107, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 111, 112, 32, 36, 108, 97, 98, 101, 108, 36, 49, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 56, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 55, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 95, 105, 102, 32, 36, 108, 97, 98, 101, 108, 36, 49, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 45, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 98, 114, 32, 36, 108, 97, 98, 101, 108, 36, 49, 51, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 53, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 114, 101, 116, 117, 114, 110, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 54, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 103, 108, 111, 98, 97, 108, 46, 115, 101, 116, 32, 36, 95, 95, 119, 97, 115, 109, 45, 105, 110, 116, 114, 105, 110, 115, 105, 99, 115, 45, 116, 101, 109, 112, 45, 105, 54, 52, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 115, 101, 116, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 48, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 41, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 51, 109, 117, 108, 51, 77, 117, 108, 51, 109, 117, 108, 49, 55, 104, 48, 55, 48, 101, 57, 97, 49, 99, 54, 57, 102, 97, 101, 99, 53, 98, 69, 32, 40, 59, 32, 49, 53, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 51, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 52, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 53, 32, 105, 51, 50, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 54, 32, 105, 51, 50, 41, 10, 32, 32, 40, 105, 54, 52, 46, 111, 114, 10, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 108, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 119, 114, 97, 112, 95, 105, 54, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 53, 53, 51, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 53, 53, 51, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 114, 95, 117, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 100, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 53, 53, 51, 53, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 109, 117, 108, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 52, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 51, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 105, 54, 52, 46, 101, 120, 116, 101, 110, 100, 95, 105, 51, 50, 95, 117, 10, 32, 32, 32, 32, 40, 105, 51, 50, 46, 111, 114, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 115, 104, 108, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 49, 54, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 97, 110, 100, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 54, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 51, 50, 46, 99, 111, 110, 115, 116, 32, 54, 53, 53, 51, 53, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 115, 100, 105, 118, 51, 68, 105, 118, 51, 100, 105, 118, 49, 55, 104, 101, 55, 56, 102, 99, 52, 56, 51, 101, 52, 49, 100, 55, 101, 99, 55, 69, 32, 40, 59, 32, 49, 54, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 100, 105, 118, 95, 117, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 40, 102, 117, 110, 99, 32, 36, 95, 90, 78, 49, 55, 99, 111, 109, 112, 105, 108, 101, 114, 95, 98, 117, 105, 108, 116, 105, 110, 115, 51, 105, 110, 116, 52, 115, 100, 105, 118, 51, 77, 111, 100, 52, 109, 111, 100, 95, 49, 55, 104, 50, 99, 98, 98, 55, 98, 98, 102, 51, 54, 101, 52, 49, 100, 54, 56, 69, 32, 40, 59, 32, 49, 55, 32, 59, 41, 32, 40, 116, 121, 112, 101, 32, 36, 48, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 48, 32, 105, 54, 52, 41, 32, 40, 112, 97, 114, 97, 109, 32, 36, 118, 97, 114, 36, 49, 32, 105, 54, 52, 41, 32, 40, 114, 101, 115, 117, 108, 116, 32, 105, 54, 52, 41, 10, 32, 32, 40, 108, 111, 99, 97, 108, 32, 36, 118, 97, 114, 36, 50, 32, 105, 54, 52, 41, 10, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 40, 105, 54, 52, 46, 114, 101, 109, 95, 117, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 117, 98, 10, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 120, 111, 114, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 116, 101, 101, 32, 36, 118, 97, 114, 36, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 115, 104, 114, 95, 115, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 105, 54, 52, 46, 99, 111, 110, 115, 116, 32, 54, 51, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 49, 41, 10, 32, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 48, 41, 10, 32, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 41, 10, 32, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 32, 41, 10, 32, 32, 32, 40, 108, 111, 99, 97, 108, 46, 103, 101, 116, 32, 36, 118, 97, 114, 36, 50, 41, 10, 32, 32, 41, 10, 32, 41, 10, 32, 59, 59, 32, 99, 117, 115, 116, 111, 109, 32, 115, 101, 99, 116, 105, 111, 110, 32, 34, 108, 105, 110, 107, 105, 110, 103, 34, 44, 32, 115, 105, 122, 101, 32, 51, 10, 41, 10, 0
 };
 
 namespace wasm {
diff --git a/binaryen/src/passes/pass.cpp b/binaryen/src/passes/pass.cpp
--- a/binaryen/src/passes/pass.cpp
+++ b/binaryen/src/passes/pass.cpp
@@ -126,12 +126,6 @@
   registerPass("emit-target-features",
                "emit the target features section in the output",
                createEmitTargetFeaturesPass);
-  registerPass("emscripten-pic",
-               "Convert PIC ABI from llvm to emscripten",
-               createEmscriptenPICPass);
-  registerPass("emscripten-pic-main-module",
-               "Convert PIC ABI from llvm to emscripten",
-               createEmscriptenPICMainModulePass);
   registerPass("extract-function",
                "leaves just one function (useful for debugging)",
                createExtractFunctionPass);
@@ -190,6 +184,10 @@
   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);
@@ -299,10 +297,6 @@
   registerPass("rereloop",
                "re-optimize control flow using the relooper algorithm",
                createReReloopPass);
-  registerPass("replace-stack-pointer",
-               "Replace llvm-generated stack pointer global with calls with "
-               "imported functions.",
-               createReplaceStackPointerPass);
   registerPass(
     "rse", "remove redundant local.sets", createRedundantSetEliminationPass);
   registerPass("roundtrip",
@@ -339,9 +333,6 @@
   registerPass("souperify-single-use",
                "emit Souper IR in text form (single-use nodes only)",
                createSouperifySingleUsePass);
-  registerPass("spill-pointers",
-               "spill pointers to the C stack (useful for Boehm-style GC)",
-               createSpillPointersPass);
   registerPass("stub-unsupported-js",
                "stub out unsupported JS operations",
                createStubUnsupportedJSOpsPass);
@@ -410,6 +401,7 @@
     add("local-cse");
   }
   add("dce");
+  add("remove-unused-names");
   add("remove-unused-brs");
   add("remove-unused-names");
   add("optimize-instructions");
@@ -542,28 +534,34 @@
 
 void PassRunner::run() {
   static const int passDebug = getPassDebug();
-  if (!isNested && (options.debug || passDebug)) {
+  // Emit logging information when asked for. At passDebug level 1+ we log
+  // the main passes, while in 2 we also log nested ones. Note that for
+  // nested ones we can only emit their name - we can't validate, or save the
+  // file, or print, as the wasm may be in an intermediate state that is not
+  // valid.
+  if (options.debug || (passDebug == 2 || (passDebug && !isNested))) {
     // for debug logging purposes, run each pass in full before running the
     // other
     auto totalTime = std::chrono::duration<double>(0);
-    size_t padding = 0;
     WasmValidator::Flags validationFlags = WasmValidator::Minimal;
     if (options.validateGlobally) {
       validationFlags = validationFlags | WasmValidator::Globally;
     }
-    std::cerr << "[PassRunner] running passes..." << std::endl;
+    auto what = isNested ? "nested passes" : "passes";
+    std::cerr << "[PassRunner] running " << what << std::endl;
+    size_t padding = 0;
     for (auto& pass : passes) {
       padding = std::max(padding, pass->name.size());
     }
-    if (passDebug >= 3) {
+    if (passDebug >= 3 && !isNested) {
       dumpWast("before", wasm);
     }
     for (auto& pass : passes) {
       // ignoring the time, save a printout of the module before, in case this
       // pass breaks it, so we can print the before and after
       std::stringstream moduleBefore;
-      if (passDebug == 2) {
-        WasmPrinter::printModule(wasm, moduleBefore);
+      if (passDebug == 2 && !isNested) {
+        moduleBefore << *wasm << '\n';
       }
       // prepare to run
       std::cerr << "[PassRunner]   running pass: " << pass->name << "... ";
@@ -582,11 +580,11 @@
       std::chrono::duration<double> diff = after - before;
       std::cerr << diff.count() << " seconds." << std::endl;
       totalTime += diff;
-      if (options.validate) {
+      if (options.validate && !isNested) {
         // validate, ignoring the time
         std::cerr << "[PassRunner]   (validating)\n";
         if (!WasmValidator().validate(*wasm, validationFlags)) {
-          WasmPrinter::printModule(wasm);
+          std::cout << *wasm << '\n';
           if (passDebug >= 2) {
             Fatal() << "Last pass (" << pass->name
                     << ") broke validation. Here is the module before: \n"
@@ -603,12 +601,12 @@
         dumpWast(pass->name, wasm);
       }
     }
-    std::cerr << "[PassRunner] passes took " << totalTime.count() << " seconds."
-              << std::endl;
-    if (options.validate) {
+    std::cerr << "[PassRunner] " << what << " took " << totalTime.count()
+              << " seconds." << std::endl;
+    if (options.validate && !isNested) {
       std::cerr << "[PassRunner] (final validation)\n";
       if (!WasmValidator().validate(*wasm, validationFlags)) {
-        WasmPrinter::printModule(wasm);
+        std::cout << *wasm << '\n';
         Fatal() << "final module does not validate\n";
       }
     }
@@ -672,7 +670,6 @@
 }
 
 void PassRunner::doAdd(std::unique_ptr<Pass> pass) {
-  pass->prepareToRun(this, wasm);
   passes.emplace_back(std::move(pass));
 }
 
diff --git a/binaryen/src/passes/passes.h b/binaryen/src/passes/passes.h
--- a/binaryen/src/passes/passes.h
+++ b/binaryen/src/passes/passes.h
@@ -41,8 +41,6 @@
 Pass* createDuplicateImportEliminationPass();
 Pass* createDuplicateFunctionEliminationPass();
 Pass* createEmitTargetFeaturesPass();
-Pass* createEmscriptenPICPass();
-Pass* createEmscriptenPICMainModulePass();
 Pass* createExtractFunctionPass();
 Pass* createFlattenPass();
 Pass* createFuncCastEmulationPass();
@@ -63,6 +61,7 @@
 Pass* createInstrumentLocalsPass();
 Pass* createInstrumentMemoryPass();
 Pass* createLoopInvariantCodeMotionPass();
+Pass* createMemory64LoweringPass();
 Pass* createMemoryPackingPass();
 Pass* createMergeBlocksPass();
 Pass* createMergeLocalsPass();
@@ -99,7 +98,6 @@
 Pass* createRemoveUnusedNamesPass();
 Pass* createReorderFunctionsPass();
 Pass* createReorderLocalsPass();
-Pass* createReplaceStackPointerPass();
 Pass* createReReloopPass();
 Pass* createRedundantSetEliminationPass();
 Pass* createRoundTripPass();
@@ -118,7 +116,6 @@
 Pass* createStripTargetFeaturesPass();
 Pass* createSouperifyPass();
 Pass* createSouperifySingleUsePass();
-Pass* createSpillPointersPass();
 Pass* createStubUnsupportedJSOpsPass();
 Pass* createSSAifyPass();
 Pass* createSSAifyNoMergePass();
diff --git a/binaryen/src/passes/wasm-intrinsics.wat b/binaryen/src/passes/wasm-intrinsics.wat
--- a/binaryen/src/passes/wasm-intrinsics.wat
+++ b/binaryen/src/passes/wasm-intrinsics.wat
@@ -26,8 +26,6 @@
  (export "__wasm_i64_srem" (func $__wasm_i64_srem))
  (export "__wasm_i64_urem" (func $__wasm_i64_urem))
  (export "__wasm_i64_mul" (func $__wasm_i64_mul))
- (export "__wasm_trunc_f32" (func $__wasm_trunc_f32))
- (export "__wasm_trunc_f64" (func $__wasm_trunc_f64))
  (export "__wasm_ctz_i32" (func $__wasm_ctz_i32))
  (export "__wasm_ctz_i64" (func $__wasm_ctz_i64))
  (export "__wasm_rotl_i32" (func $__wasm_rotl_i32))
@@ -142,38 +140,6 @@
   (call $_ZN17compiler_builtins3int3mul3Mul3mul17h070e9a1c69faec5bE
    (local.get $var$0)
    (local.get $var$1)
-  )
- )
- ;; lowering of the f32.trunc instruction, rounds to the nearest integer,
- ;; towards zero
- (func $__wasm_trunc_f32 (; 5 ;) (type $1) (param $var$0 f32) (result f32)
-  (select
-   (f32.ceil
-    (local.get $var$0)
-   )
-   (f32.floor
-    (local.get $var$0)
-   )
-   (f32.lt
-    (local.get $var$0)
-    (f32.const 0)
-   )
-  )
- )
- ;; lowering of the f64.trunc instruction, rounds to the nearest integer,
- ;; towards zero
- (func $__wasm_trunc_f64 (; 6 ;) (type $2) (param $var$0 f64) (result f64)
-  (select
-   (f64.ceil
-    (local.get $var$0)
-   )
-   (f64.floor
-    (local.get $var$0)
-   )
-   (f64.lt
-    (local.get $var$0)
-    (f64.const 0)
-   )
   )
  )
  ;; lowering of the i32.ctz instruction, counting the number of zeros in $var$0
diff --git a/binaryen/src/shared-constants.h b/binaryen/src/shared-constants.h
--- a/binaryen/src/shared-constants.h
+++ b/binaryen/src/shared-constants.h
@@ -39,9 +39,12 @@
 extern Name EXPORT;
 extern Name IMPORT;
 extern Name TABLE;
+extern Name GLOBAL;
 extern Name ELEM;
 extern Name LOCAL;
 extern Name TYPE;
+extern Name REF;
+extern Name NULL_;
 extern Name CALL;
 extern Name CALL_IMPORT;
 extern Name CALL_INDIRECT;
@@ -64,7 +67,6 @@
 extern Name SHARED;
 extern Name EVENT;
 extern Name ATTR;
-extern Name ASSIGN_GOT_ENTRIES;
 
 } // namespace wasm
 
diff --git a/binaryen/src/shell-interface.h b/binaryen/src/shell-interface.h
--- a/binaryen/src/shell-interface.h
+++ b/binaryen/src/shell-interface.h
@@ -98,7 +98,7 @@
   void importGlobals(std::map<Name, Literals>& globals, Module& wasm) override {
     // add spectest globals
     ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) {
-      if (import->module == SPECTEST && import->base.startsWith(GLOBAL)) {
+      if (import->module == SPECTEST && import->base.startsWith("global_")) {
         TODO_SINGLE_COMPOUND(import->type);
         switch (import->type.getBasic()) {
           case Type::i32:
diff --git a/binaryen/src/support/bits.cpp b/binaryen/src/support/bits.cpp
--- a/binaryen/src/support/bits.cpp
+++ b/binaryen/src/support/bits.cpp
@@ -157,6 +157,38 @@
 
 int ceilLog2(uint64_t v) { return 64 - countLeadingZeroes(v - 1); }
 
+bool isPowerOf2InvertibleFloat(float v) {
+  // Power of two floating points should have zero as their significands,
+  // so here we just mask the exponent range of "v" and compare it with the
+  // unmasked input value. If they are equal, our value is a power of
+  // two. Also, we reject all values which are less than the minimal possible
+  // power of two or greater than the maximum possible power of two.
+  // We check values only with exponent in more limited ranges
+  // [-126..+126] for floats and [-1022..+1022] for doubles for avoiding
+  // overflows and reject NaNs, infinity and denormals. We also reject
+  // "asymmetric exponents", like +1023, because the range of
+  // (non-NaN, non-infinity) values is -1022..+1023, and it is convenient in
+  // optimizations to depend on being able to invert a power of two without
+  // losing precision.
+  // This function used in OptimizeInstruction pass.
+  const uint32_t MIN_POT = 0x01U << 23;  // 0x1p-126
+  const uint32_t MAX_POT = 0xFDU << 23;  // 0x1p+126
+  const uint32_t EXP_MASK = 0xFFU << 23; // mask only exponent
+  const uint32_t SIGN_MASK = ~0U >> 1;   // mask everything except sign
+  auto u = bit_cast<uint32_t>(v) & SIGN_MASK;
+  return u >= MIN_POT && u <= MAX_POT && (u & EXP_MASK) == u;
+}
+
+bool isPowerOf2InvertibleFloat(double v) {
+  // See isPowerOf2InvertibleFloat(float)
+  const uint64_t MIN_POT = 0x001ULL << 52;  // 0x1p-1022
+  const uint64_t MAX_POT = 0x7FDULL << 52;  // 0x1p+1022
+  const uint64_t EXP_MASK = 0x7FFULL << 52; // mask only exponent
+  const uint64_t SIGN_MASK = ~0ULL >> 1;    // mask everything except sign
+  auto u = bit_cast<uint64_t>(v) & SIGN_MASK;
+  return u >= MIN_POT && u <= MAX_POT && (u & EXP_MASK) == u;
+}
+
 uint32_t log2(uint32_t v) {
   if (!isPowerOf2(v)) {
     WASM_UNREACHABLE("value should be a power of two");
@@ -164,7 +196,7 @@
   return 31 - countLeadingZeroes(v);
 }
 
-uint32_t pow2(uint32_t v) { return 1 << v; }
+uint32_t pow2(uint32_t v) { return v < 32 ? 1 << v : 0; }
 
 } // namespace Bits
 
diff --git a/binaryen/src/support/bits.h b/binaryen/src/support/bits.h
--- a/binaryen/src/support/bits.h
+++ b/binaryen/src/support/bits.h
@@ -77,6 +77,9 @@
   return v != 0 && (v & (v - 1)) == 0;
 }
 
+bool isPowerOf2InvertibleFloat(float);
+bool isPowerOf2InvertibleFloat(double);
+
 template<typename T, typename U> inline static T rotateLeft(T val, U count) {
   auto value = typename std::make_unsigned<T>::type(val);
   U mask = sizeof(T) * CHAR_BIT - 1;
diff --git a/binaryen/src/support/file.h b/binaryen/src/support/file.h
--- a/binaryen/src/support/file.h
+++ b/binaryen/src/support/file.h
@@ -15,7 +15,7 @@
  */
 
 //
-// FIle helpers.
+// File helpers.
 //
 
 #ifndef wasm_support_file_h
diff --git a/binaryen/src/support/small_vector.h b/binaryen/src/support/small_vector.h
--- a/binaryen/src/support/small_vector.h
+++ b/binaryen/src/support/small_vector.h
@@ -46,6 +46,7 @@
       push_back(item);
     }
   }
+  SmallVector(size_t initialSize) { resize(initialSize); }
 
   T& operator[](size_t i) {
     if (i < N) {
@@ -109,6 +110,13 @@
   void clear() {
     usedFixed = 0;
     flexible.clear();
+  }
+
+  void resize(size_t newSize) {
+    usedFixed = std::min(N, newSize);
+    if (newSize > N) {
+      flexible.resize(newSize - N);
+    }
   }
 
   bool operator==(const SmallVector<T, N>& other) const {
diff --git a/binaryen/src/support/space.h b/binaryen/src/support/space.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/support/space.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_support_space_h
+#define wasm_support_space_h
+
+#include "utilities.h"
+#include <wasm.h>
+
+namespace wasm {
+
+struct DisjointSpans {
+  // A span of form [a, b), i.e., that does not include the end point.
+  struct Span {
+    Address left, right;
+
+    bool checkOverlap(const Span& other) const {
+      return !(left >= other.right || right <= other.left);
+    }
+  };
+
+  struct SortByLeft {
+    bool operator()(const Span& left, const Span& right) const {
+      return left.left < right.left ||
+             (left.left == right.left && left.right < right.right);
+    }
+  };
+
+  // The spans seen so far. Guaranteed to be disjoint.
+  std::set<Span, SortByLeft> spans;
+
+  // Adds an item and checks overlap while doing so, returning true if such
+  // overlap exists.
+  bool addAndCheckOverlap(Span span) {
+    // Insert the new span. We can then find its predecessor and successor.
+    // They are disjoint by assumption, so the question is then does the new
+    // span overlap with them, or not.
+    decltype(spans)::iterator iter;
+    bool inserted;
+    std::tie(iter, inserted) = spans.insert(span);
+    if (!inserted) {
+      // This exact span was already there, so there is definite overlap.
+      return true;
+    }
+    // Check predecessor and successor, if they exist.
+    if (iter != spans.begin() && std::prev(iter)->checkOverlap(span)) {
+      return true;
+    }
+    if (std::next(iter) != spans.end() && std::next(iter)->checkOverlap(span)) {
+      return true;
+    }
+    return false;
+  }
+
+  // Inefficient - mostly for testing.
+  void add(Span span) { addAndCheckOverlap(span); }
+
+  // Inefficient - mostly for testing.
+  bool checkOverlap(Span span) {
+    bool existsBefore = spans.find(span) != spans.end();
+    auto hasOverlap = addAndCheckOverlap(span);
+    if (!existsBefore) {
+      spans.erase(span);
+    }
+    return hasOverlap;
+  }
+};
+
+} // namespace wasm
+
+#endif // wasm_support_space_h
diff --git a/binaryen/src/support/string.h b/binaryen/src/support/string.h
--- a/binaryen/src/support/string.h
+++ b/binaryen/src/support/string.h
@@ -115,6 +115,10 @@
   return input.substr(0, size);
 }
 
+inline bool isNumber(const std::string& str) {
+  return !str.empty() && std::all_of(str.begin(), str.end(), ::isdigit);
+}
+
 } // namespace String
 
 } // namespace wasm
diff --git a/binaryen/src/tools/execution-results.h b/binaryen/src/tools/execution-results.h
--- a/binaryen/src/tools/execution-results.h
+++ b/binaryen/src/tools/execution-results.h
@@ -29,6 +29,14 @@
 struct LoggingExternalInterface : public ShellExternalInterface {
   Loggings& loggings;
 
+  struct State {
+    // Legalization for JS emits get/setTempRet0 calls ("temp ret 0" means a
+    // temporary return value of 32 bits; "0" is the only important value for
+    // 64-bit legalization, which needs one such 32-bit chunk in addition to
+    // the normal return value which can handle 32 bits).
+    uint32_t tempRet0 = 0;
+  } state;
+
   LoggingExternalInterface(Loggings& loggings) : loggings(loggings) {}
 
   Literals callImport(Function* import, LiteralList& arguments) override {
@@ -40,7 +48,24 @@
         loggings.push_back(argument);
       }
       std::cout << "]\n";
+      return {};
+    } else if (import->module == ENV) {
+      if (import->base == "log_execution") {
+        std::cout << "[LoggingExternalInterface log-execution";
+        for (auto argument : arguments) {
+          std::cout << ' ' << argument;
+        }
+        std::cout << "]\n";
+        return {};
+      } else if (import->base == "setTempRet0") {
+        state.tempRet0 = arguments[0].geti32();
+        return {};
+      } else if (import->base == "getTempRet0") {
+        return {Literal(state.tempRet0)};
+      }
     }
+    std::cerr << "[LoggingExternalInterface ignoring an unknown import "
+              << import->module << " . " << import->base << '\n';
     return {};
   }
 };
@@ -69,14 +94,6 @@
         if (func->sig.results != Type::none) {
           // this has a result
           Literals ret = run(func, wasm, instance);
-          // We cannot compare funcrefs by name because function names can
-          // change (after duplicate function elimination or roundtripping)
-          // while the function contents are still the same
-          for (Literal& val : ret) {
-            if (val.type == Type::funcref && !val.isNull()) {
-              val = Literal::makeFunc(Name("funcref"));
-            }
-          }
           results[exp->name] = ret;
           // ignore the result if we hit an unreachable and returned no value
           if (ret.size() > 0) {
@@ -98,11 +115,46 @@
     ExecutionResults optimizedResults;
     optimizedResults.get(wasm);
     if (optimizedResults != *this) {
-      std::cout << "[fuzz-exec] optimization passes changed execution results";
+      std::cout << "[fuzz-exec] optimization passes changed results\n";
       exit(1);
     }
   }
 
+  bool areEqual(Literal a, Literal b) {
+    if (a.type != b.type) {
+      std::cout << "types not identical! " << a << " != " << b << '\n';
+      return false;
+    }
+    if (a.type.isRef()) {
+      // Don't compare references - only their types. There are several issues
+      // here that we can't fully handle, see
+      // https://github.com/WebAssembly/binaryen/issues/3378, but the core issue
+      // is that we are comparing results between two separate wasm modules (and
+      // a separate instance of each) - we can't really identify an identical
+      // reference between such things. We can only compare things structurally,
+      // for which we compare the types.
+      return true;
+    }
+    if (a != b) {
+      std::cout << "values not identical! " << a << " != " << b << '\n';
+      return false;
+    }
+    return true;
+  }
+
+  bool areEqual(Literals a, Literals b) {
+    if (a.size() != b.size()) {
+      std::cout << "literal counts not identical! " << a << " != " << b << '\n';
+      return false;
+    }
+    for (Index i = 0; i < a.size(); i++) {
+      if (!areEqual(a[i], b[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   bool operator==(ExecutionResults& other) {
     for (auto& iter : other.results) {
       auto name = iter.first;
@@ -111,15 +163,18 @@
         return false;
       }
       std::cout << "[fuzz-exec] comparing " << name << '\n';
-      if (results[name] != other.results[name]) {
-        std::cout << "not identical! " << results[name]
-                  << " != " << other.results[name] << "\n";
+      if (!areEqual(results[name], other.results[name])) {
         return false;
       }
     }
-    if (loggings != other.loggings) {
-      std::cout << "logging not identical!\n";
+    if (loggings.size() != other.loggings.size()) {
+      std::cout << "logging counts not identical!\n";
       return false;
+    }
+    for (Index i = 0; i < loggings.size(); i++) {
+      if (!areEqual(loggings[i], other.loggings[i])) {
+        return false;
+      }
     }
     return true;
   }
diff --git a/binaryen/src/tools/fuzzing.h b/binaryen/src/tools/fuzzing.h
--- a/binaryen/src/tools/fuzzing.h
+++ b/binaryen/src/tools/fuzzing.h
@@ -31,6 +31,7 @@
 #include <ir/find_all.h>
 #include <ir/literal-utils.h>
 #include <ir/manipulation.h>
+#include <ir/names.h>
 #include <ir/utils.h>
 #include <support/file.h>
 #include <tools/optimization-options.h>
@@ -188,6 +189,9 @@
   void setAllowOOB(bool allowOOB_) { allowOOB = allowOOB_; }
 
   void build() {
+    if (HANG_LIMIT > 0) {
+      prepareHangLimitSupport();
+    }
     if (allowMemory) {
       setupMemory();
     }
@@ -196,6 +200,7 @@
     if (wasm.features.hasExceptionHandling()) {
       setupEvents();
     }
+    modifyInitialFunctions();
     addImportLoggingSupport();
     // keep adding functions until we run out of input
     while (!finishedInput) {
@@ -205,6 +210,9 @@
     if (HANG_LIMIT > 0) {
       addHangLimitSupport();
     }
+    if (allowMemory) {
+      finalizeMemory();
+    }
     finalizeTable();
   }
 
@@ -241,7 +249,7 @@
   // the memory that we use, a small portion so that we have a good chance of
   // looking at writes (we also look outside of this region with small
   // probability) this should be a power of 2
-  static const int USABLE_MEMORY = 16;
+  const Address USABLE_MEMORY = 16;
 
   // the number of runtime iterations (function calls, loop backbranches) we
   // allow before we stop execution with a trap, to prevent hangs. 0 means
@@ -313,30 +321,37 @@
       }
       return Type(types);
     }
+    if (type.isFunction() && type != Type::funcref) {
+      // TODO: specific typed function references types.
+      return type;
+    }
     SmallVector<Type, 2> options;
     options.push_back(type); // includes itself
-    TODO_SINGLE_COMPOUND(type);
-    switch (type.getBasic()) {
-      case Type::anyref:
-        if (wasm.features.hasReferenceTypes()) {
-          options.push_back(Type::funcref);
-          options.push_back(Type::externref);
-          if (wasm.features.hasExceptionHandling()) {
-            options.push_back(Type::exnref);
+    // TODO: interesting uses of typed function types
+    // TODO: interesting subtypes of compound types
+    if (type.isBasic()) {
+      switch (type.getBasic()) {
+        case Type::anyref:
+          if (wasm.features.hasReferenceTypes()) {
+            options.push_back(Type::funcref);
+            options.push_back(Type::externref);
+            if (wasm.features.hasExceptionHandling()) {
+              options.push_back(Type::exnref);
+            }
+            if (wasm.features.hasGC()) {
+              options.push_back(Type::eqref);
+              options.push_back(Type::i31ref);
+            }
           }
+          break;
+        case Type::eqref:
           if (wasm.features.hasGC()) {
-            options.push_back(Type::eqref);
             options.push_back(Type::i31ref);
           }
-        }
-        break;
-      case Type::eqref:
-        if (wasm.features.hasGC()) {
-          options.push_back(Type::i31ref);
-        }
-        break;
-      default:
-        break;
+          break;
+        default:
+          break;
+      }
     }
     return pick(options);
   }
@@ -406,64 +421,161 @@
     wasm.addExport(
       builder.makeExport(hasher->name, hasher->name, ExternalKind::Function));
     // Export memory so JS fuzzing can use it
-    wasm.addExport(builder.makeExport("memory", "0", ExternalKind::Memory));
+    if (!wasm.getExportOrNull("memory")) {
+      wasm.addExport(builder.makeExport("memory", "0", ExternalKind::Memory));
+    }
   }
 
   void setupTable() {
     wasm.table.exists = true;
+    wasm.table.initial = wasm.table.max = 0;
     wasm.table.segments.emplace_back(builder.makeConst(int32_t(0)));
   }
 
   std::map<Type, std::vector<Name>> globalsByType;
 
   void setupGlobals() {
+    // If there were initial wasm contents, there may be imported globals. That
+    // would be a problem in the fuzzer harness as we'd error if we do not
+    // provide them (and provide the proper type, etc.).
+    // Avoid that, so that all the standard fuzzing infrastructure can always
+    // run the wasm.
+    for (auto& global : wasm.globals) {
+      if (global->imported()) {
+        // Remove import info from imported globals, and give them a simple
+        // initializer.
+        global->module = global->base = Name();
+        global->init = makeConst(global->type);
+      } else {
+        // If the initialization referred to an imported global, it no longer
+        // can point to the same global after we make it a non-imported global
+        // (as wasm doesn't allow that - you can only use an imported one).
+        if (global->init->is<GlobalGet>()) {
+          global->init = makeConst(global->type);
+        }
+      }
+    }
     for (size_t index = upTo(MAX_GLOBALS); index > 0; --index) {
       auto type = getConcreteType();
-      auto* global =
-        builder.makeGlobal(std::string("global$") + std::to_string(index),
+      auto global =
+        builder.makeGlobal(Names::getValidGlobalName(wasm, "global$"),
                            type,
                            makeConst(type),
                            Builder::Mutable);
-      wasm.addGlobal(global);
       globalsByType[type].push_back(global->name);
+      wasm.addGlobal(std::move(global));
     }
   }
 
   void setupEvents() {
     Index num = upTo(3);
     for (size_t i = 0; i < num; i++) {
-      auto* event =
-        builder.makeEvent(std::string("event$") + std::to_string(i),
+      auto event =
+        builder.makeEvent(Names::getValidEventName(wasm, "event$"),
                           WASM_EVENT_ATTRIBUTE_EXCEPTION,
                           Signature(getControlFlowType(), Type::none));
-      wasm.addEvent(event);
+      wasm.addEvent(std::move(event));
     }
   }
 
+  void finalizeMemory() {
+    for (auto& segment : wasm.memory.segments) {
+      Address maxOffset = segment.data.size();
+      if (!segment.isPassive) {
+        if (auto* offset = segment.offset->dynCast<GlobalGet>()) {
+          // Using a non-imported global in a segment offset is not valid in
+          // wasm. This can occur due to us making what used to be an imported
+          // global, in initial contents, be not imported any more. To fix that,
+          // replace such invalid things with a constant.
+          // Note that it is still possible in theory to have imported globals
+          // here, as we only do the above for initial contents. While the
+          // fuzzer doesn't do so as of the time of this comment, do a check
+          // for full generality, so that this code essentially does "if this
+          // is invalid wasm, fix it up."
+          if (!wasm.getGlobal(offset->name)->imported()) {
+            // TODO: It would be better to avoid segment overlap so that
+            //       MemoryPacking can run.
+            segment.offset =
+              builder.makeConst(Literal::makeFromInt32(0, Type::i32));
+          }
+        }
+        if (auto* offset = segment.offset->dynCast<Const>()) {
+          maxOffset = maxOffset + offset->value.getInteger();
+        }
+      }
+      wasm.memory.initial = std::max(
+        wasm.memory.initial,
+        Address((maxOffset + Memory::kPageSize - 1) / Memory::kPageSize));
+    }
+    wasm.memory.initial = std::max(wasm.memory.initial, USABLE_MEMORY);
+    // Avoid an unlimited memory size, which would make fuzzing very difficult
+    // as different VMs will run out of system memory in different ways.
+    if (wasm.memory.max == Memory::kUnlimitedSize) {
+      wasm.memory.max = wasm.memory.initial;
+    }
+    if (wasm.memory.max <= wasm.memory.initial) {
+      // To allow growth to work (which a testcase may assume), try to make the
+      // maximum larger than the initial.
+      // TODO: scan the wasm for grow instructions?
+      wasm.memory.max =
+        std::min(Address(wasm.memory.initial + 1), Address(Memory::kMaxSize32));
+    }
+    // Avoid an imported memory (which the fuzz harness would need to handle).
+    wasm.memory.module = wasm.memory.base = Name();
+  }
+
   void finalizeTable() {
-    wasm.table.initial = wasm.table.segments[0].data.size();
+    for (auto& segment : wasm.table.segments) {
+      // If the offset is a global that was imported (which is ok) but no
+      // longer is (not ok) we need to change that.
+      if (auto* offset = segment.offset->dynCast<GlobalGet>()) {
+        if (!wasm.getGlobal(offset->name)->imported()) {
+          // TODO: the segments must not overlap...
+          segment.offset =
+            builder.makeConst(Literal::makeFromInt32(0, Type::i32));
+        }
+      }
+      Address maxOffset = segment.data.size();
+      if (auto* offset = segment.offset->dynCast<Const>()) {
+        maxOffset = maxOffset + offset->value.getInteger();
+      }
+      wasm.table.initial = std::max(wasm.table.initial, maxOffset);
+    }
     wasm.table.max =
       oneIn(2) ? Address(Table::kUnlimitedSize) : wasm.table.initial;
+    // Avoid an imported table (which the fuzz harness would need to handle).
+    wasm.table.module = wasm.table.base = Name();
   }
 
-  const Name HANG_LIMIT_GLOBAL = "hangLimit";
+  Name HANG_LIMIT_GLOBAL;
 
+  void prepareHangLimitSupport() {
+    HANG_LIMIT_GLOBAL = Names::getValidGlobalName(wasm, "hangLimit");
+  }
+
   void addHangLimitSupport() {
-    auto* glob = builder.makeGlobal(HANG_LIMIT_GLOBAL,
-                                    Type::i32,
-                                    builder.makeConst(int32_t(HANG_LIMIT)),
-                                    Builder::Mutable);
-    wasm.addGlobal(glob);
+    auto glob = builder.makeGlobal(HANG_LIMIT_GLOBAL,
+                                   Type::i32,
+                                   builder.makeConst(int32_t(HANG_LIMIT)),
+                                   Builder::Mutable);
+    wasm.addGlobal(std::move(glob));
 
+    Name exportName = "hangLimitInitializer";
+    auto funcName = Names::getValidFunctionName(wasm, exportName);
     auto* func = new Function;
-    func->name = "hangLimitInitializer";
+    func->name = funcName;
     func->sig = Signature(Type::none, Type::none);
-    func->body =
-      builder.makeGlobalSet(glob->name, builder.makeConst(int32_t(HANG_LIMIT)));
+    func->body = builder.makeGlobalSet(HANG_LIMIT_GLOBAL,
+                                       builder.makeConst(int32_t(HANG_LIMIT)));
     wasm.addFunction(func);
 
+    if (wasm.getExportOrNull(exportName)) {
+      // We must export our actual hang limit function - remove anything
+      // previously existing.
+      wasm.removeExport(exportName);
+    }
     auto* export_ = new Export;
-    export_->name = func->name;
+    export_->name = exportName;
     export_->value = func->name;
     export_->kind = ExternalKind::Function;
     wasm.addExport(export_);
@@ -496,41 +608,66 @@
 
   // function generation state
 
-  Function* func = nullptr;
-  std::vector<Expression*> breakableStack; // things we can break to
-  Index labelIndex;
+  struct FunctionCreationContext {
+    TranslateToFuzzReader& parent;
 
-  // a list of things relevant to computing the odds of an infinite loop,
-  // which we try to minimize the risk of
-  std::vector<Expression*> hangStack;
+    Function* func;
 
-  std::map<Type, std::vector<Index>>
-    typeLocals; // type => list of locals with that type
+    std::vector<Expression*> breakableStack; // things we can break to
+    Index labelIndex = 0;
 
+    // a list of things relevant to computing the odds of an infinite loop,
+    // which we try to minimize the risk of
+    std::vector<Expression*> hangStack;
+
+    // type => list of locals with that type
+    std::map<Type, std::vector<Index>> typeLocals;
+
+    FunctionCreationContext(TranslateToFuzzReader& parent, Function* func)
+      : parent(parent), func(func) {
+      parent.funcContext = this;
+    }
+
+    ~FunctionCreationContext() {
+      if (parent.HANG_LIMIT > 0) {
+        parent.addHangLimitChecks(func);
+      }
+      assert(breakableStack.empty());
+      assert(hangStack.empty());
+      parent.funcContext = nullptr;
+    }
+  };
+
+  FunctionCreationContext* funcContext = nullptr;
+
+  Index numAddedFunctions = 0;
+
   Function* addFunction() {
     LOGGING_PERCENT = upToSquared(100);
-    Index num = wasm.functions.size();
-    func = new Function;
-    func->name = std::string("func_") + std::to_string(num);
-    assert(typeLocals.empty());
+    auto* func = new Function;
+    func->name = Names::getValidFunctionName(wasm, "func");
+    FunctionCreationContext context(*this, func);
+    assert(funcContext->typeLocals.empty());
     Index numParams = upToSquared(MAX_PARAMS);
     std::vector<Type> params;
     params.reserve(numParams);
     for (Index i = 0; i < numParams; i++) {
       auto type = getSingleConcreteType();
-      typeLocals[type].push_back(params.size());
+      funcContext->typeLocals[type].push_back(params.size());
       params.push_back(type);
     }
     func->sig = Signature(Type(params), getControlFlowType());
     Index numVars = upToSquared(MAX_VARS);
     for (Index i = 0; i < numVars; i++) {
       auto type = getConcreteType();
-      typeLocals[type].push_back(params.size() + func->vars.size());
+      if (type.isRef() && !type.isNullable()) {
+        // We can't use a nullable type as a var, which is null-initialized.
+        continue;
+      }
+      funcContext->typeLocals[type].push_back(params.size() +
+                                              func->vars.size());
       func->vars.push_back(type);
     }
-    labelIndex = 0;
-    assert(breakableStack.empty());
-    assert(hangStack.empty());
     // with small chance, make the body unreachable
     auto bodyType = func->sig.results;
     if (oneIn(10)) {
@@ -558,15 +695,11 @@
       fixLabels(func);
     }
     // Add hang limit checks after all other operations on the function body.
-    if (HANG_LIMIT > 0) {
-      addHangLimitChecks(func);
-    }
-    assert(breakableStack.empty());
-    assert(hangStack.empty());
     wasm.addFunction(func);
     // export some, but not all (to allow inlining etc.). make sure to
     // export at least one, though, to keep each testcase interesting
-    if (num == 0 || oneIn(2)) {
+    if ((numAddedFunctions == 0 || oneIn(2)) &&
+        !wasm.getExportOrNull(func->name)) {
       auto* export_ = new Export;
       export_->name = func->name;
       export_->value = func->name;
@@ -577,8 +710,7 @@
     while (oneIn(3) && !finishedInput) {
       wasm.table.segments[0].data.push_back(func->name);
     }
-    // cleanup
-    typeLocals.clear();
+    numAddedFunctions++;
     return func;
   }
 
@@ -675,7 +807,16 @@
 
       void visitExpression(Expression* curr) {
         if (parent.oneIn(10)) {
-          // Replace it!
+          // For constants, perform only a small tweaking in some cases.
+          if (auto* c = curr->dynCast<Const>()) {
+            if (parent.oneIn(2)) {
+              c->value = parent.tweak(c->value);
+              return;
+            }
+          }
+          // TODO: more minor tweaks to immediates, like making a load atomic or
+          // not, changing an offset, etc.
+          // Perform a general replacement.
           // (This is not always valid due to nesting of labels, but
           // we'll fix that up later.)
           replaceCurrent(parent.make(curr->type));
@@ -774,10 +915,83 @@
     ReFinalize().walkFunctionInModule(func, &wasm);
   }
 
+  void modifyInitialFunctions() {
+    if (wasm.functions.empty()) {
+      return;
+    }
+    // Pick a chance to fuzz the contents of a function.
+    const int RESOLUTION = 10;
+    auto chance = upTo(RESOLUTION + 1);
+    for (auto& ref : wasm.functions) {
+      auto* func = ref.get();
+      FunctionCreationContext context(*this, func);
+      if (func->imported()) {
+        // We can't allow extra imports, as the fuzzing infrastructure wouldn't
+        // know what to provide.
+        func->module = func->base = Name();
+        func->body = make(func->sig.results);
+      }
+      // Optionally, fuzz the function contents.
+      if (upTo(RESOLUTION) >= chance) {
+        dropToLog(func);
+        // TODO add some locals? and the rest of addFunction's operations?
+        // TODO: interposition, replace initial a(b) with a(RANDOM_THING(b))
+        // TODO: if we add OOB checks after creation, then we can do it on
+        //       initial contents too, and it may be nice to *not* run these
+        //       passes, like we don't run them on new functions. But, we may
+        //       still want to run them some of the time, at least, so that we
+        //       check variations on initial testcases even at the risk of OOB.
+        recombine(func);
+        mutate(func);
+        fixLabels(func);
+      }
+    }
+    // Remove a start function - the fuzzing harness expects code to run only
+    // from exports.
+    wasm.start = Name();
+  }
+
+  // Initial wasm contents may have come from a test that uses the drop pattern:
+  //
+  //  (drop ..something interesting..)
+  //
+  // The dropped interesting thing is optimized to some other interesting thing
+  // by a pass, and we verify it is the expected one. But this does not use the
+  // value in a way the fuzzer can notice. Replace some drops with a logging
+  // operation instead.
+  void dropToLog(Function* func) {
+    // Don't always do this.
+    if (oneIn(2)) {
+      return;
+    }
+    struct Modder : public PostWalker<Modder> {
+      Module& wasm;
+      TranslateToFuzzReader& parent;
+
+      Modder(Module& wasm, TranslateToFuzzReader& parent)
+        : wasm(wasm), parent(parent) {}
+
+      void visitDrop(Drop* curr) {
+        if (parent.isLoggableType(curr->value->type) && parent.oneIn(2)) {
+          replaceCurrent(parent.builder.makeCall(std::string("log-") +
+                                                   curr->value->type.toString(),
+                                                 {curr->value},
+                                                 Type::none));
+        }
+      }
+    };
+    Modder modder(wasm, *this);
+    modder.walk(func->body);
+  }
+
   // the fuzzer external interface sends in zeros (simpler to compare
   // across invocations from JS or wasm-opt etc.). Add invocations in
   // the wasm, so they run everywhere
   void addInvocations(Function* func) {
+    Name name = func->name.str + std::string("_invoker");
+    if (wasm.getFunctionOrNull(name) || wasm.getExportOrNull(name)) {
+      return;
+    }
     std::vector<Expression*> invocations;
     while (oneIn(2) && !finishedInput) {
       std::vector<Expression*> args;
@@ -799,19 +1013,19 @@
       return;
     }
     auto* invoker = new Function;
-    invoker->name = func->name.str + std::string("_invoker");
+    invoker->name = name;
     invoker->sig = Signature(Type::none, Type::none);
     invoker->body = builder.makeBlock(invocations);
     wasm.addFunction(invoker);
     auto* export_ = new Export;
-    export_->name = invoker->name;
-    export_->value = invoker->name;
+    export_->name = name;
+    export_->value = name;
     export_->kind = ExternalKind::Function;
     wasm.addExport(export_);
   }
 
   Name makeLabel() {
-    return std::string("label$") + std::to_string(labelIndex++);
+    return std::string("label$") + std::to_string(funcContext->labelIndex++);
   }
 
   // Weighting for the core make* methods. Some nodes are important enough that
@@ -870,13 +1084,16 @@
                 WeightedOption{&Self::makeGlobalGet, Important},
                 WeightedOption{&Self::makeConst, Important});
     if (canMakeControlFlow) {
-      options.add(FeatureSet::MVP,
-                  WeightedOption{&Self::makeBlock, Important},
-                  WeightedOption{&Self::makeIf, Important},
-                  WeightedOption{&Self::makeLoop, Important},
-                  WeightedOption{&Self::makeBreak, Important},
-                  &Self::makeCall,
-                  &Self::makeCallIndirect);
+      options
+        .add(FeatureSet::MVP,
+             WeightedOption{&Self::makeBlock, Important},
+             WeightedOption{&Self::makeIf, Important},
+             WeightedOption{&Self::makeLoop, Important},
+             WeightedOption{&Self::makeBreak, Important},
+             &Self::makeCall,
+             &Self::makeCallIndirect)
+        .add(FeatureSet::TypedFunctionReferences | FeatureSet::ReferenceTypes,
+             &Self::makeCallRef);
     }
     if (type.isSingle()) {
       options
@@ -906,6 +1123,7 @@
       options.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
                   &Self::makeI31New);
     }
+    // TODO: struct.get and other GC things
     return (this->*pick(options))(type);
   }
 
@@ -935,7 +1153,9 @@
            &Self::makeNop,
            &Self::makeGlobalSet)
       .add(FeatureSet::BulkMemory, &Self::makeBulkMemory)
-      .add(FeatureSet::Atomics, &Self::makeAtomic);
+      .add(FeatureSet::Atomics, &Self::makeAtomic)
+      .add(FeatureSet::TypedFunctionReferences | FeatureSet::ReferenceTypes,
+           &Self::makeCallRef);
     return (this->*pick(options))(Type::none);
   }
 
@@ -943,22 +1163,25 @@
     using Self = TranslateToFuzzReader;
     auto options = FeatureOptions<Expression* (Self::*)(Type)>();
     using WeightedOption = decltype(options)::WeightedOption;
-    options.add(FeatureSet::MVP,
-                WeightedOption{&Self::makeLocalSet, VeryImportant},
-                WeightedOption{&Self::makeBlock, Important},
-                WeightedOption{&Self::makeIf, Important},
-                WeightedOption{&Self::makeLoop, Important},
-                WeightedOption{&Self::makeBreak, Important},
-                WeightedOption{&Self::makeStore, Important},
-                WeightedOption{&Self::makeUnary, Important},
-                WeightedOption{&Self::makeBinary, Important},
-                WeightedOption{&Self::makeUnreachable, Important},
-                &Self::makeCall,
-                &Self::makeCallIndirect,
-                &Self::makeSelect,
-                &Self::makeSwitch,
-                &Self::makeDrop,
-                &Self::makeReturn);
+    options
+      .add(FeatureSet::MVP,
+           WeightedOption{&Self::makeLocalSet, VeryImportant},
+           WeightedOption{&Self::makeBlock, Important},
+           WeightedOption{&Self::makeIf, Important},
+           WeightedOption{&Self::makeLoop, Important},
+           WeightedOption{&Self::makeBreak, Important},
+           WeightedOption{&Self::makeStore, Important},
+           WeightedOption{&Self::makeUnary, Important},
+           WeightedOption{&Self::makeBinary, Important},
+           WeightedOption{&Self::makeUnreachable, Important},
+           &Self::makeCall,
+           &Self::makeCallIndirect,
+           &Self::makeSelect,
+           &Self::makeSwitch,
+           &Self::makeDrop,
+           &Self::makeReturn)
+      .add(FeatureSet::TypedFunctionReferences | FeatureSet::ReferenceTypes,
+           &Self::makeCallRef);
     return (this->*pick(options))(Type::unreachable);
   }
 
@@ -975,8 +1198,8 @@
     }
     assert(type == Type::unreachable);
     Expression* ret = nullptr;
-    if (func->sig.results.isConcrete()) {
-      ret = makeTrivial(func->sig.results);
+    if (funcContext->func->sig.results.isConcrete()) {
+      ret = makeTrivial(funcContext->func->sig.results);
     }
     return builder.makeReturn(ret);
   }
@@ -987,7 +1210,7 @@
     auto* ret = builder.makeBlock();
     ret->type = type; // so we have it during child creation
     ret->name = makeLabel();
-    breakableStack.push_back(ret);
+    funcContext->breakableStack.push_back(ret);
     Index num = upToSquared(BLOCK_FACTOR - 1); // we add another later
     if (nesting >= NESTING_LIMIT / 2) {
       // smaller blocks past the limit
@@ -1012,7 +1235,7 @@
     } else {
       ret->list.push_back(make(type));
     }
-    breakableStack.pop_back();
+    funcContext->breakableStack.pop_back();
     if (type.isConcrete()) {
       ret->finalize(type);
     } else {
@@ -1030,8 +1253,8 @@
     auto* ret = wasm.allocator.alloc<Loop>();
     ret->type = type; // so we have it during child creation
     ret->name = makeLabel();
-    breakableStack.push_back(ret);
-    hangStack.push_back(ret);
+    funcContext->breakableStack.push_back(ret);
+    funcContext->hangStack.push_back(ret);
     // either create random content, or do something more targeted
     if (oneIn(2)) {
       ret->body = makeMaybeBlock(type);
@@ -1044,8 +1267,8 @@
       list.push_back(make(type)); // final element, so we have the right type
       ret->body = builder.makeBlock(list, type);
     }
-    breakableStack.pop_back();
-    hangStack.pop_back();
+    funcContext->breakableStack.pop_back();
+    funcContext->hangStack.pop_back();
     ret->finalize(type);
     return ret;
   }
@@ -1077,26 +1300,26 @@
 
   Expression* makeIf(Type type) {
     auto* condition = makeCondition();
-    hangStack.push_back(nullptr);
+    funcContext->hangStack.push_back(nullptr);
     auto* ret =
       buildIf({condition, makeMaybeBlock(type), makeMaybeBlock(type)}, type);
-    hangStack.pop_back();
+    funcContext->hangStack.pop_back();
     return ret;
   }
 
   Expression* makeBreak(Type type) {
-    if (breakableStack.empty()) {
+    if (funcContext->breakableStack.empty()) {
       return makeTrivial(type);
     }
     Expression* condition = nullptr;
     if (type != Type::unreachable) {
-      hangStack.push_back(nullptr);
+      funcContext->hangStack.push_back(nullptr);
       condition = makeCondition();
     }
     // we need to find a proper target to break to; try a few times
     int tries = TRIES;
     while (tries-- > 0) {
-      auto* target = pick(breakableStack);
+      auto* target = pick(funcContext->breakableStack);
       auto name = getTargetName(target);
       auto valueType = getTargetType(target);
       if (type.isConcrete()) {
@@ -1106,7 +1329,7 @@
           continue;
         }
         auto* ret = builder.makeBreak(name, make(type), condition);
-        hangStack.pop_back();
+        funcContext->hangStack.pop_back();
         return ret;
       } else if (type == Type::none) {
         if (valueType != Type::none) {
@@ -1114,7 +1337,7 @@
           continue;
         }
         auto* ret = builder.makeBreak(name, nullptr, condition);
-        hangStack.pop_back();
+        funcContext->hangStack.pop_back();
         return ret;
       } else {
         assert(type == Type::unreachable);
@@ -1126,9 +1349,9 @@
         // to a loop, we prefer there to be a condition along the
         // way, to reduce the chance of infinite looping
         size_t conditions = 0;
-        int i = hangStack.size();
+        int i = funcContext->hangStack.size();
         while (--i >= 0) {
-          auto* item = hangStack[i];
+          auto* item = funcContext->hangStack[i];
           if (item == nullptr) {
             conditions++;
           } else if (auto* loop = item->cast<Loop>()) {
@@ -1162,22 +1385,21 @@
     }
     // we failed to find something
     if (type != Type::unreachable) {
-      hangStack.pop_back();
+      funcContext->hangStack.pop_back();
     }
     return makeTrivial(type);
   }
 
   Expression* makeCall(Type type) {
-    // seems ok, go on
     int tries = TRIES;
     bool isReturn;
     while (tries-- > 0) {
-      Function* target = func;
+      Function* target = funcContext->func;
       if (!wasm.functions.empty() && !oneIn(wasm.functions.size())) {
         target = pick(wasm.functions).get();
       }
       isReturn = type == Type::unreachable && wasm.features.hasTailCall() &&
-                 func->sig.results == target->sig.results;
+                 funcContext->func->sig.results == target->sig.results;
       if (target->sig.results != type && !isReturn) {
         continue;
       }
@@ -1189,7 +1411,7 @@
       return builder.makeCall(target->name, args, type, isReturn);
     }
     // we failed to find something
-    return make(type);
+    return makeTrivial(type);
   }
 
   Expression* makeCallIndirect(Type type) {
@@ -1206,7 +1428,7 @@
       // TODO: handle unreachable
       targetFn = wasm.getFunction(data[i]);
       isReturn = type == Type::unreachable && wasm.features.hasTailCall() &&
-                 func->sig.results == targetFn->sig.results;
+                 funcContext->func->sig.results == targetFn->sig.results;
       if (targetFn->sig.results == type || isReturn) {
         break;
       }
@@ -1215,7 +1437,7 @@
         i = 0;
       }
       if (i == start) {
-        return make(type);
+        return makeTrivial(type);
       }
     }
     // with high probability, make sure the type is valid  otherwise, most are
@@ -1233,8 +1455,37 @@
     return builder.makeCallIndirect(target, args, targetFn->sig, isReturn);
   }
 
+  Expression* makeCallRef(Type type) {
+    // look for a call target with the right type
+    Function* target;
+    bool isReturn;
+    size_t i = 0;
+    while (1) {
+      if (i == TRIES || wasm.functions.empty()) {
+        // We can't find a proper target, give up.
+        return makeTrivial(type);
+      }
+      // TODO: handle unreachable
+      target = wasm.functions[upTo(wasm.functions.size())].get();
+      isReturn = type == Type::unreachable && wasm.features.hasTailCall() &&
+                 funcContext->func->sig.results == target->sig.results;
+      if (target->sig.results == type || isReturn) {
+        break;
+      }
+      i++;
+    }
+    std::vector<Expression*> args;
+    for (const auto& type : target->sig.params) {
+      args.push_back(make(type));
+    }
+    auto targetType = Type(HeapType(target->sig), Nullable);
+    // TODO: half the time make a completely random item with that type.
+    return builder.makeCallRef(
+      builder.makeRefFunc(target->name, targetType), args, type, isReturn);
+  }
+
   Expression* makeLocalGet(Type type) {
-    auto& locals = typeLocals[type];
+    auto& locals = funcContext->typeLocals[type];
     if (locals.empty()) {
       return makeConst(type);
     }
@@ -1249,7 +1500,7 @@
     } else {
       valueType = getConcreteType();
     }
-    auto& locals = typeLocals[valueType];
+    auto& locals = funcContext->typeLocals[valueType];
     if (locals.empty()) {
       return makeTrivial(type);
     }
@@ -1536,6 +1787,43 @@
     return store;
   }
 
+  // Makes a small change to a constant value.
+  Literal tweak(Literal value) {
+    auto type = value.type;
+    if (type.isVector()) {
+      // TODO: tweak each lane?
+      return value;
+    }
+    // +- 1
+    switch (upTo(5)) {
+      case 0:
+        value = value.add(Literal::makeNegOne(type));
+        break;
+      case 1:
+        value = value.add(Literal::makeOne(type));
+        break;
+      default: {
+      }
+    }
+    // For floats, optionally add a non-integer adjustment in +- [-1, 1]
+    if (type.isFloat() && oneIn(2)) {
+      const int RANGE = 1000;
+      auto RANGE_LITERAL = Literal::makeFromInt32(RANGE, type);
+      // adjustment -> [0, 2 * RANGE]
+      auto adjustment = Literal::makeFromInt32(upTo(2 * RANGE + 1), type);
+      // adjustment -> [-RANGE, RANGE]
+      adjustment = adjustment.sub(RANGE_LITERAL);
+      // adjustment -> [-1, 1]
+      adjustment = adjustment.div(RANGE_LITERAL);
+      value = value.add(adjustment);
+    }
+    // Flip sign.
+    if (oneIn(2)) {
+      value = value.mul(Literal::makeNegOne(type));
+    }
+    return value;
+  }
+
   Literal makeLiteral(Type type) {
     if (type == Type::v128) {
       // generate each lane individually for random lane interpretation
@@ -1587,38 +1875,6 @@
       }
     }
 
-    // Optional tweaking of the value by a small adjustment.
-    auto tweak = [this, type](Literal value) {
-      // +- 1
-      switch (upTo(5)) {
-        case 0:
-          value = value.add(Literal::makeNegOne(type));
-          break;
-        case 1:
-          value = value.add(Literal::makeOne(type));
-          break;
-        default: {
-        }
-      }
-      // For floats, optionally add a non-integer adjustment in +- [-1, 1]
-      if (type.isFloat() && oneIn(2)) {
-        const int RANGE = 1000;
-        auto RANGE_LITERAL = Literal::makeFromInt32(RANGE, type);
-        // adjustment -> [0, 2 * RANGE]
-        auto adjustment = Literal::makeFromInt32(upTo(2 * RANGE + 1), type);
-        // adjustment -> [-RANGE, RANGE]
-        adjustment = adjustment.sub(RANGE_LITERAL);
-        // adjustment -> [-1, 1]
-        adjustment = adjustment.div(RANGE_LITERAL);
-        value = value.add(adjustment);
-      }
-      // Flip sign.
-      if (oneIn(2)) {
-        value = value.mul(Literal::makeNegOne(type));
-      }
-      return value;
-    };
-
     switch (upTo(4)) {
       case 0: {
         // totally random, entire range
@@ -1803,19 +2059,41 @@
       // 'func' is the pointer to the last created function and can be null when
       // we set up globals (before we create any functions), in which case we
       // can't use ref.func.
-      if (type == Type::funcref && func && oneIn(2)) {
+      if (type == Type::funcref && funcContext && oneIn(2)) {
         // First set to target to the last created function, and try to select
         // among other existing function if possible
-        Function* target = func;
+        Function* target = funcContext->func;
         if (!wasm.functions.empty() && !oneIn(wasm.functions.size())) {
           target = pick(wasm.functions).get();
         }
-        return builder.makeRefFunc(target->name);
+        auto type = Type(HeapType(target->sig), Nullable);
+        return builder.makeRefFunc(target->name, type);
       }
       if (type == Type::i31ref) {
         return builder.makeI31New(makeConst(Type::i32));
       }
-      return builder.makeRefNull(type);
+      if (oneIn(2) && type.isNullable()) {
+        return builder.makeRefNull(type);
+      }
+      // TODO: randomize the order
+      for (auto& func : wasm.functions) {
+        // FIXME: RefFunc type should be non-nullable, but we emit nullable
+        //        types for now.
+        if (type == Type(HeapType(func->sig), Nullable)) {
+          return builder.makeRefFunc(func->name, type);
+        }
+      }
+      // We failed to find a function, so create a null reference if we can.
+      if (type.isNullable()) {
+        return builder.makeRefNull(type);
+      }
+      // Last resort: create a function.
+      auto* func = wasm.addFunction(builder.makeFunction(
+        Names::getValidFunctionName(wasm, "ref_func_target"),
+        type.getHeapType().getSignature(),
+        {},
+        builder.makeUnreachable()));
+      return builder.makeRefFunc(func->name, type);
     }
     if (type.isTuple()) {
       std::vector<Expression*> operands;
@@ -1890,9 +2168,7 @@
                                     AnyTrueVecI16x8,
                                     AllTrueVecI16x8,
                                     AnyTrueVecI32x4,
-                                    AllTrueVecI32x4,
-                                    AnyTrueVecI64x2,
-                                    AllTrueVecI64x2),
+                                    AllTrueVecI32x4),
                                make(Type::v128)});
           }
           case Type::funcref:
@@ -2012,6 +2288,7 @@
             return buildUnary({SplatVecF64x2, make(Type::f64)});
           case 4:
             return buildUnary({pick(NotVec128,
+                                    // TODO: i8x16.popcnt once merged
                                     NegVecI8x16,
                                     NegVecI16x8,
                                     NegVecI32x4,
@@ -2240,6 +2517,9 @@
                                  MinUVecI8x16,
                                  MaxSVecI8x16,
                                  MaxUVecI8x16,
+                                 // TODO: avgr_u
+                                 // TODO: q15mulr_sat_s
+                                 // TODO: extmul
                                  AddVecI16x8,
                                  AddSatSVecI16x8,
                                  AddSatUVecI16x8,
@@ -2306,7 +2586,7 @@
 
   Expression* makeSwitch(Type type) {
     assert(type == Type::unreachable);
-    if (breakableStack.empty()) {
+    if (funcContext->breakableStack.empty()) {
       return make(type);
     }
     // we need to find proper targets to break to; try a bunch
@@ -2314,7 +2594,7 @@
     std::vector<Name> names;
     Type valueType = Type::unreachable;
     while (tries-- > 0) {
-      auto* target = pick(breakableStack);
+      auto* target = pick(funcContext->breakableStack);
       auto name = getTargetName(target);
       auto currValueType = getTargetType(target);
       if (names.empty()) {
@@ -2343,8 +2623,9 @@
   }
 
   Expression* makeReturn(Type type) {
-    return builder.makeReturn(
-      func->sig.results.isConcrete() ? make(func->sig.results) : nullptr);
+    return builder.makeReturn(funcContext->func->sig.results.isConcrete()
+                                ? make(funcContext->func->sig.results)
+                                : nullptr);
   }
 
   Expression* makeNop(Type type) {
@@ -2424,17 +2705,13 @@
     auto* ptr = makePointer();
     if (oneIn(2)) {
       auto* value = make(type);
-      return builder.makeAtomicRMW(pick(AtomicRMWOp::Add,
-                                        AtomicRMWOp::Sub,
-                                        AtomicRMWOp::And,
-                                        AtomicRMWOp::Or,
-                                        AtomicRMWOp::Xor,
-                                        AtomicRMWOp::Xchg),
-                                   bytes,
-                                   offset,
-                                   ptr,
-                                   value,
-                                   type);
+      return builder.makeAtomicRMW(
+        pick(RMWAdd, RMWSub, RMWAnd, RMWOr, RMWXor, RMWXchg),
+        bytes,
+        offset,
+        ptr,
+        value,
+        type);
     } else {
       auto* expected = make(type);
       auto* replacement = make(type);
@@ -2451,6 +2728,7 @@
     if (type != Type::v128) {
       return makeSIMDExtract(type);
     }
+    // TODO: Add SIMDLoadStoreLane once it is generally available
     switch (upTo(7)) {
       case 0:
         return makeUnary(Type::v128);
@@ -2762,6 +3040,7 @@
              Type::anyref,
              Type::eqref,
              Type::i31ref));
+    // TODO: emit typed function references types
   }
 
   Type getSingleConcreteType() { return pick(getSingleConcreteTypes()); }
@@ -2787,12 +3066,24 @@
 
   Type getEqReferenceType() { return pick(getEqReferenceTypes()); }
 
+  Type getMVPType() {
+    return pick(items(FeatureOptions<Type>().add(
+      FeatureSet::MVP, Type::i32, Type::i64, Type::f32, Type::f64)));
+  }
+
   Type getTupleType() {
     std::vector<Type> elements;
-    size_t numElements = 2 + upTo(MAX_TUPLE_SIZE - 1);
-    elements.resize(numElements);
-    for (size_t i = 0; i < numElements; ++i) {
-      elements[i] = getSingleConcreteType();
+    size_t maxElements = 2 + upTo(MAX_TUPLE_SIZE - 1);
+    for (size_t i = 0; i < maxElements; ++i) {
+      auto type = getSingleConcreteType();
+      // Don't add a non-nullable type into a tuple, as currently we can't spill
+      // them into locals (that would require a "let").
+      if (!type.isNullable()) {
+        elements.push_back(type);
+      }
+    }
+    while (elements.size() < 2) {
+      elements.push_back(getMVPType());
     }
     return Type(elements);
   }
diff --git a/binaryen/src/tools/optimization-options.h b/binaryen/src/tools/optimization-options.h
--- a/binaryen/src/tools/optimization-options.h
+++ b/binaryen/src/tools/optimization-options.h
@@ -193,7 +193,14 @@
         "-ffm",
         "Optimize floats without handling corner cases of NaNs and rounding",
         Options::Arguments::Zero,
-        [this](Options*, const std::string&) { passOptions.fastMath = true; });
+        [this](Options*, const std::string&) { passOptions.fastMath = true; })
+      .add("--zero-filled-memory",
+           "-uim",
+           "Assume that an imported memory will be zero-initialized",
+           Options::Arguments::Zero,
+           [this](Options*, const std::string&) {
+             passOptions.zeroFilledMemory = true;
+           });
     // add passes in registry
     for (const auto& p : PassRegistry::get()->getRegisteredNames()) {
       (*this).add(
diff --git a/binaryen/src/tools/tool-options.h b/binaryen/src/tools/tool-options.h
--- a/binaryen/src/tools/tool-options.h
+++ b/binaryen/src/tools/tool-options.h
@@ -89,6 +89,8 @@
       .addFeature(FeatureSet::Multivalue, "multivalue functions")
       .addFeature(FeatureSet::GC, "garbage collection")
       .addFeature(FeatureSet::Memory64, "memory64")
+      .addFeature(FeatureSet::TypedFunctionReferences,
+                  "typed function references")
       .add("--no-validation",
            "-n",
            "Disables validation, assumes inputs are correct",
@@ -140,7 +142,7 @@
     return *this;
   }
 
-  void applyFeatures(Module& module) {
+  void applyFeatures(Module& module) const {
     if (hasFeatureOptions) {
       if (!detectFeatures && module.hasFeaturesSection) {
         FeatureSet optionsFeatures = FeatureSet::MVP;
diff --git a/binaryen/src/tools/wasm-ctor-eval.cpp b/binaryen/src/tools/wasm-ctor-eval.cpp
--- a/binaryen/src/tools/wasm-ctor-eval.cpp
+++ b/binaryen/src/tools/wasm-ctor-eval.cpp
@@ -24,6 +24,7 @@
 
 #include <memory>
 
+#include "asmjs/shared-constants.h"
 #include "ir/global-utils.h"
 #include "ir/import-utils.h"
 #include "ir/literal-utils.h"
@@ -465,7 +466,7 @@
   options.applyFeatures(wasm);
 
   if (!WasmValidator().validate(wasm)) {
-    WasmPrinter::printModule(&wasm);
+    std::cout << wasm << '\n';
     Fatal() << "error in validating input";
   }
 
diff --git a/binaryen/src/tools/wasm-dis.cpp b/binaryen/src/tools/wasm-dis.cpp
--- a/binaryen/src/tools/wasm-dis.cpp
+++ b/binaryen/src/tools/wasm-dis.cpp
@@ -22,7 +22,6 @@
 #include "support/command-line.h"
 #include "support/file.h"
 #include "wasm-io.h"
-#include "wasm-printing.h"
 
 using namespace cashew;
 using namespace wasm;
@@ -76,8 +75,7 @@
     std::cerr << "Printing..." << std::endl;
   }
   Output output(options.extra["output"], Flags::Text);
-  WasmPrinter::printModule(&wasm, output.getStream());
-  output << '\n';
+  output.getStream() << wasm << '\n';
 
   if (options.debug) {
     std::cerr << "Done." << std::endl;
diff --git a/binaryen/src/tools/wasm-emscripten-finalize.cpp b/binaryen/src/tools/wasm-emscripten-finalize.cpp
--- a/binaryen/src/tools/wasm-emscripten-finalize.cpp
+++ b/binaryen/src/tools/wasm-emscripten-finalize.cpp
@@ -30,7 +30,6 @@
 #include "wasm-binary.h"
 #include "wasm-emscripten.h"
 #include "wasm-io.h"
-#include "wasm-printing.h"
 #include "wasm-validator.h"
 
 #define DEBUG_TYPE "emscripten"
@@ -51,7 +50,6 @@
   bool debugInfo = false;
   bool DWARF = false;
   bool sideModule = false;
-  bool legacyPIC = true;
   bool legalizeJavaScriptFFI = true;
   bool bigInt = false;
   bool checkStackOverflow = false;
@@ -114,9 +112,7 @@
          "",
          "Use new/llvm PIC abi",
          Options::Arguments::Zero,
-         [&legacyPIC](Options* o, const std::string& argument) {
-           legacyPIC = false;
-         })
+         [&](Options* o, const std::string& argument) {})
     .add("--input-source-map",
          "-ism",
          "Consume source map from the specified file",
@@ -225,32 +221,7 @@
   options.applyFeatures(wasm);
 
   BYN_TRACE_WITH_TYPE("emscripten-dump", "Module before:\n");
-  BYN_DEBUG_WITH_TYPE("emscripten-dump",
-                      WasmPrinter::printModule(&wasm, std::cerr));
-
-  uint32_t dataSize = 0;
-
-  if (!sideModule) {
-    if (globalBase == INVALID_BASE) {
-      Fatal() << "globalBase must be set";
-    }
-    Export* dataEndExport = wasm.getExport("__data_end");
-    if (dataEndExport == nullptr) {
-      Fatal() << "__data_end export not found";
-    }
-    Global* dataEnd = wasm.getGlobal(dataEndExport->value);
-    if (dataEnd == nullptr) {
-      Fatal() << "__data_end global not found";
-    }
-    if (dataEnd->type != Type::i32) {
-      Fatal() << "__data_end global has wrong type";
-    }
-    if (dataEnd->imported()) {
-      Fatal() << "__data_end must not be an imported global";
-    }
-    Const* dataEndConst = dataEnd->init->cast<Const>();
-    dataSize = dataEndConst->value.geti32() - globalBase;
-  }
+  BYN_DEBUG_WITH_TYPE("emscripten-dump", std::cerr << &wasm);
 
   EmscriptenGlueGenerator generator(wasm);
   generator.standalone = standaloneWasm;
@@ -259,14 +230,7 @@
   generator.onlyI64DynCalls = onlyI64DynCalls;
   generator.noDynCalls = noDynCalls;
 
-  std::vector<Name> initializerFunctions;
-
-  // The wasm backend emits "__indirect_function_table" as the import name for
-  // the table, while older emscripten expects "table"
-  if (wasm.table.imported() && !minimizeWasmChanges) {
-    wasm.table.base = Name("table");
-  }
-  wasm.updateMaps();
+  Name initializerFunction;
 
   if (!standaloneWasm) {
     // This is also not needed in standalone mode since standalone mode uses
@@ -278,7 +242,7 @@
   passRunner.setDebug(options.debug);
   passRunner.setDebugInfo(debugInfo);
 
-  if (checkStackOverflow && !sideModule) {
+  if (checkStackOverflow) {
     if (!standaloneWasm) {
       // In standalone mode we don't set a handler at all.. which means
       // just trap on overflow.
@@ -288,18 +252,6 @@
     passRunner.add("stack-check");
   }
 
-  if (sideModule) {
-    passRunner.add("replace-stack-pointer");
-  }
-
-  if (legacyPIC) {
-    if (sideModule) {
-      passRunner.add("emscripten-pic");
-    } else {
-      passRunner.add("emscripten-pic-main-module");
-    }
-  }
-
   if (!noDynCalls && !standaloneWasm) {
     // If not standalone wasm then JS is relevant and we need dynCalls.
     if (onlyI64DynCalls) {
@@ -329,24 +281,18 @@
 
   if (sideModule) {
     BYN_TRACE("finalizing as side module\n");
-    generator.generatePostInstantiateFunction();
+    // The emscripten PIC ABI still expects a function named
+    // __post_instantiate to be exported by side module.
+    if (auto* e = wasm.getExportOrNull(WASM_CALL_CTORS)) {
+      e->name = "__post_instantiate";
+    }
   } else {
     BYN_TRACE("finalizing as regular module\n");
-    generator.internalizeStackPointerGlobal();
-    // For side modules these gets called via __post_instantiate
-    if (Function* F = wasm.getFunctionOrNull(ASSIGN_GOT_ENTRIES)) {
-      auto* ex = new Export();
-      ex->value = F->name;
-      ex->name = F->name;
-      ex->kind = ExternalKind::Function;
-      wasm.addExport(ex);
-      initializerFunctions.push_back(F->name);
-    }
     // Costructors get called from crt1 in wasm standalone mode.
     // Unless there is no entry point.
     if (!standaloneWasm || !wasm.getExportOrNull("_start")) {
       if (auto* e = wasm.getExportOrNull(WASM_CALL_CTORS)) {
-        initializerFunctions.push_back(e->name);
+        initializerFunction = e->name;
       }
     }
   }
@@ -354,7 +300,7 @@
   BYN_TRACE("generated metadata\n");
   // Substantial changes to the wasm are done, enough to create the metadata.
   std::string metadata =
-    generator.generateEmscriptenMetadata(dataSize, initializerFunctions);
+    generator.generateEmscriptenMetadata(initializerFunction);
 
   // Finally, separate out data segments if relevant (they may have been needed
   // for metadata).
@@ -367,8 +313,7 @@
   }
 
   BYN_TRACE_WITH_TYPE("emscripten-dump", "Module after:\n");
-  BYN_DEBUG_WITH_TYPE("emscripten-dump",
-                      WasmPrinter::printModule(&wasm, std::cerr));
+  BYN_DEBUG_WITH_TYPE("emscripten-dump", std::cerr << wasm << '\n');
 
   // Write the modified wasm if the user asked us to, either by specifying an
   // output file, or requesting text output (which goes to stdout by default).
diff --git a/binaryen/src/tools/wasm-metadce.cpp b/binaryen/src/tools/wasm-metadce.cpp
--- a/binaryen/src/tools/wasm-metadce.cpp
+++ b/binaryen/src/tools/wasm-metadce.cpp
@@ -511,7 +511,7 @@
 
   if (options.passOptions.validate) {
     if (!WasmValidator().validate(wasm)) {
-      WasmPrinter::printModule(&wasm);
+      std::cout << wasm << '\n';
       Fatal() << "error in validating input";
     }
   }
diff --git a/binaryen/src/tools/wasm-opt.cpp b/binaryen/src/tools/wasm-opt.cpp
--- a/binaryen/src/tools/wasm-opt.cpp
+++ b/binaryen/src/tools/wasm-opt.cpp
@@ -34,7 +34,6 @@
 #include "wasm-binary.h"
 #include "wasm-interpreter.h"
 #include "wasm-io.h"
-#include "wasm-printing.h"
 #include "wasm-s-parser.h"
 #include "wasm-validator.h"
 #include "wasm2c-wrapper.h"
@@ -81,6 +80,7 @@
   bool fuzzExecAfter = false;
   std::string extraFuzzCommand;
   bool translateToFuzz = false;
+  std::string initialFuzz;
   bool fuzzPasses = false;
   bool fuzzMemory = true;
   bool fuzzOOB = true;
@@ -141,6 +141,13 @@
       "fuzzing",
       Options::Arguments::Zero,
       [&](Options* o, const std::string& arguments) { translateToFuzz = true; })
+    .add("--initial-fuzz",
+         "-if",
+         "Initial wasm content in translate-to-fuzz (-ttf) mode",
+         Options::Arguments::One,
+         [&initialFuzz](Options* o, const std::string& argument) {
+           initialFuzz = argument;
+         })
     .add("--fuzz-passes",
          "-fp",
          "Pick a random set of passes to run, useful for fuzzing. this depends "
@@ -219,12 +226,18 @@
     // to print would not be reached).
     if (std::find(options.passes.begin(), options.passes.end(), "print") !=
         options.passes.end()) {
-      WasmPrinter::printModule(&wasm);
+      std::cout << wasm << '\n';
     }
     Fatal() << message;
   };
 
-  if (!translateToFuzz) {
+  // In normal (non-translate-to-fuzz) mode we read the input file. In
+  // translate-to-fuzz mode the input file is the random data, and used later
+  // down in TranslateToFuzzReader, but there is also an optional initial fuzz
+  // file that if it exists we read it, then add more fuzz on top.
+  if (!translateToFuzz || initialFuzz.size()) {
+    std::string inputFile =
+      translateToFuzz ? initialFuzz : options.extra["infile"];
     ModuleReader reader;
     // Enable DWARF parsing if we were asked for debug info, and were not
     // asked to remove it.
@@ -232,7 +245,7 @@
                     !willRemoveDebugInfo(options.passes));
     reader.setProfile(options.profile);
     try {
-      reader.read(options.extra["infile"], wasm, inputSourceMapFilename);
+      reader.read(inputFile, wasm, inputSourceMapFilename);
     } catch (ParseException& p) {
       p.dump(std::cerr);
       std::cerr << '\n';
@@ -253,8 +266,8 @@
         exitOnInvalidWasm("error validating input");
       }
     }
-  } else {
-    // translate-to-fuzz
+  }
+  if (translateToFuzz) {
     options.applyFeatures(wasm);
     TranslateToFuzzReader reader(wasm, options.extra["infile"]);
     if (fuzzPasses) {
@@ -265,7 +278,7 @@
     reader.build();
     if (options.passOptions.validate) {
       if (!WasmValidator().validate(wasm)) {
-        WasmPrinter::printModule(&wasm);
+        std::cout << wasm << '\n';
         Fatal() << "error after translate-to-fuzz";
       }
     }
diff --git a/binaryen/src/tools/wasm-reduce.cpp b/binaryen/src/tools/wasm-reduce.cpp
--- a/binaryen/src/tools/wasm-reduce.cpp
+++ b/binaryen/src/tools/wasm-reduce.cpp
@@ -287,7 +287,9 @@
           currCommand += " -g ";
         }
         if (!binary) {
-          currCommand += " -S ";
+          currCommand += " -S --all-features ";
+        } else {
+          currCommand += " --detect-features ";
         }
         if (verbose) {
           std::cerr << "|    trying pass command: " << currCommand << "\n";
@@ -578,7 +580,10 @@
           continue; // no conversion
         }
         Expression* fixed = nullptr;
-        TODO_SINGLE_COMPOUND(curr->type);
+        if (!curr->type.isBasic() || !child->type.isBasic()) {
+          // TODO: handle compound types
+          continue;
+        }
         switch (curr->type.getBasic()) {
           case Type::i32: {
             TODO_SINGLE_COMPOUND(child->type);
@@ -937,6 +942,11 @@
           replaceCurrent(Builder(*getModule()).replaceWithIdenticalType(curr));
         }
       }
+      void visitRefFunc(RefFunc* curr) {
+        if (names.count(curr->func)) {
+          replaceCurrent(Builder(*getModule()).replaceWithIdenticalType(curr));
+        }
+      }
       void visitExport(Export* curr) {
         if (names.count(curr->value)) {
           exportsToRemove.push_back(curr->name);
@@ -1034,7 +1044,12 @@
         builder->makeConstantExpression(Literal::makeZeros(curr->type));
       return tryToReplaceCurrent(n);
     }
-    Const* c = builder->makeConst(int32_t(0));
+    if (!curr->type.isNumber()) {
+      return false;
+    }
+    // It's a number: try to replace it with a 0 or a 1 (trying more values
+    // could make sense too, but these handle most cases).
+    auto* c = builder->makeConst(Literal::makeZero(curr->type));
     if (tryToReplaceCurrent(c)) {
       return true;
     }
@@ -1204,10 +1219,12 @@
                "(read-written) binary\n";
   {
     // read and write it
-    auto cmd = Path::getBinaryenBinaryTool("wasm-opt") + " " + input +
-               " --detect-features -o " + test;
+    auto cmd =
+      Path::getBinaryenBinaryTool("wasm-opt") + " " + input + " -o " + test;
     if (!binary) {
-      cmd += " -S";
+      cmd += " -S --all-features";
+    } else {
+      cmd += " --detect-features";
     }
     ProgramResult readWrite(cmd);
     if (readWrite.failed()) {
diff --git a/binaryen/src/tools/wasm-shell.cpp b/binaryen/src/tools/wasm-shell.cpp
--- a/binaryen/src/tools/wasm-shell.cpp
+++ b/binaryen/src/tools/wasm-shell.cpp
@@ -28,7 +28,6 @@
 #include "support/command-line.h"
 #include "support/file.h"
 #include "wasm-interpreter.h"
-#include "wasm-printing.h"
 #include "wasm-s-parser.h"
 #include "wasm-validator.h"
 
@@ -311,7 +310,7 @@
         modules[moduleName]->features = FeatureSet::All;
         bool valid = WasmValidator().validate(*modules[moduleName]);
         if (!valid) {
-          WasmPrinter::printModule(modules[moduleName].get());
+          std::cout << *modules[moduleName] << '\n';
           Fatal() << "module failed to validate, see above";
         }
         run_asserts(moduleName,
diff --git a/binaryen/src/tools/wasm-split.cpp b/binaryen/src/tools/wasm-split.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/src/tools/wasm-split.cpp
@@ -0,0 +1,671 @@
+/*
+ * 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.
+ */
+
+// wasm-split: Split a module in two or instrument a module to inform future
+// splitting.
+
+#include "ir/module-splitting.h"
+#include "ir/module-utils.h"
+#include "ir/names.h"
+#include "support/file.h"
+#include "support/name.h"
+#include "support/utilities.h"
+#include "tool-options.h"
+#include "wasm-builder.h"
+#include "wasm-io.h"
+#include "wasm-type.h"
+#include "wasm-validator.h"
+#include <sstream>
+
+using namespace wasm;
+
+namespace {
+
+const std::string DEFAULT_PROFILE_EXPORT("__write_profile");
+
+std::set<Name> parseNameList(const std::string& list) {
+  std::set<Name> names;
+  std::istringstream stream(list);
+  for (std::string name; std::getline(stream, name, ',');) {
+    names.insert(name);
+  }
+  return names;
+}
+
+struct WasmSplitOptions : ToolOptions {
+  bool verbose = false;
+  bool emitBinary = true;
+
+  bool instrument = false;
+
+  std::string profileFile;
+  std::string profileExport = DEFAULT_PROFILE_EXPORT;
+
+  std::set<Name> keepFuncs;
+  std::set<Name> splitFuncs;
+
+  std::string input;
+  std::string output;
+  std::string primaryOutput;
+  std::string secondaryOutput;
+
+  std::string importNamespace;
+  std::string placeholderNamespace;
+  std::string exportPrefix;
+
+  // A hack to ensure the split and instrumented modules have the same table
+  // size when using Emscripten's SPLIT_MODULE mode with dynamic linking. TODO:
+  // Figure out a more elegant solution for that use case and remove this.
+  int initialTableSize = -1;
+
+  WasmSplitOptions();
+  bool validate();
+  void parse(int argc, const char* argv[]);
+};
+
+WasmSplitOptions::WasmSplitOptions()
+  : ToolOptions("wasm-split",
+                "Split a module into a primary module and a secondary "
+                "module or instrument a module to gather a profile that "
+                "can inform future splitting.") {
+  (*this)
+    .add("--instrument",
+         "",
+         "Instrument the module to generate a profile that can be used to "
+         "guide splitting",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { instrument = true; })
+    .add(
+      "--profile",
+      "",
+      "The profile to use to guide splitting. May not be used with "
+      "--instrument.",
+      Options::Arguments::One,
+      [&](Options* o, const std::string& argument) { profileFile = argument; })
+    .add("--profile-export",
+         "",
+         "The export name of the function the embedder calls to write the "
+         "profile into memory. Defaults to `__write_profile`. Must be used "
+         "with --instrument.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           profileExport = argument;
+         })
+    .add("--keep-funcs",
+         "",
+         "Comma-separated list of functions to keep in the primary module, "
+         "regardless of any profile.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           keepFuncs = parseNameList(argument);
+         })
+    .add("--split-funcs",
+         "",
+         "Comma-separated list of functions to split into the secondary "
+         "module, regardless of any profile. If there is no profile, then "
+         "this defaults to all functions defined in the module.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           splitFuncs = parseNameList(argument);
+         })
+    .add("--output",
+         "-o",
+         "Output file. Only usable with --instrument.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) { output = argument; })
+    .add("--primary-output",
+         "-o1",
+         "Output file for the primary module. Not usable with --instrument.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           primaryOutput = argument;
+         })
+    .add("--secondary-output",
+         "-o2",
+         "Output file for the secondary module. Not usable with --instrument.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           secondaryOutput = argument;
+         })
+    .add("--import-namespace",
+         "",
+         "The namespace from which to import objects from the primary "
+         "module into the secondary module.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           importNamespace = argument;
+         })
+    .add("--placeholder-namespace",
+         "",
+         "The namespace from which to import placeholder functions into "
+         "the primary module.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           placeholderNamespace = argument;
+         })
+    .add(
+      "--export-prefix",
+      "",
+      "An identifying prefix to prepend to new export names created "
+      "by module splitting.",
+      Options::Arguments::One,
+      [&](Options* o, const std::string& argument) { exportPrefix = argument; })
+    .add("--verbose",
+         "-v",
+         "Verbose output mode. Prints the functions that will be kept "
+         "and split out when splitting a module.",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) {
+           verbose = true;
+           quiet = false;
+         })
+    .add("--emit-text",
+         "-S",
+         "Emit text instead of binary for the output file or files.",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& argument) { emitBinary = false; })
+    .add("--debuginfo",
+         "-g",
+         "Emit names section in wasm binary (or full debuginfo in wast)",
+         Options::Arguments::Zero,
+         [&](Options* o, const std::string& arguments) {
+           passOptions.debugInfo = true;
+         })
+    .add("--initial-table",
+         "",
+         "A hack to ensure the split and instrumented modules have the same "
+         "table size when using Emscripten's SPLIT_MODULE mode with dynamic "
+         "linking. TODO: Figure out a more elegant solution for that use "
+         "case and remove this.",
+         Options::Arguments::One,
+         [&](Options* o, const std::string& argument) {
+           initialTableSize = std::stoi(argument);
+         })
+    .add_positional(
+      "INFILE",
+      Options::Arguments::One,
+      [&](Options* o, const std::string& argument) { input = argument; });
+}
+
+bool WasmSplitOptions::validate() {
+  bool valid = true;
+  auto fail = [&](auto msg) {
+    std::cerr << "error: " << msg << "\n";
+    valid = false;
+  };
+
+  if (!input.size()) {
+    fail("no input file");
+  }
+  if (instrument) {
+    using Opt = std::pair<const std::string&, const std::string>;
+    for (auto& opt : {Opt{profileFile, "--profile"},
+                      Opt{primaryOutput, "primary output"},
+                      Opt{secondaryOutput, "secondary output"},
+                      Opt{importNamespace, "--import-namespace"},
+                      Opt{placeholderNamespace, "--placeholder-namespace"},
+                      Opt{exportPrefix, "--export-prefix"}}) {
+      if (opt.first.size()) {
+        fail(opt.second + " cannot be used with --instrument");
+      }
+    }
+    if (keepFuncs.size()) {
+      fail("--keep-funcs cannot be used with --instrument");
+    }
+    if (splitFuncs.size()) {
+      fail("--split-funcs cannot be used with --instrument");
+    }
+  } else {
+    if (output.size()) {
+      fail(
+        "must provide separate primary and secondary output with -o1 and -o2");
+    }
+    if (profileExport != DEFAULT_PROFILE_EXPORT) {
+      fail("--profile-export must be used with --instrument");
+    }
+  }
+
+  std::vector<Name> impossible;
+  std::set_intersection(keepFuncs.begin(),
+                        keepFuncs.end(),
+                        splitFuncs.begin(),
+                        splitFuncs.end(),
+                        std::inserter(impossible, impossible.end()));
+  for (auto& func : impossible) {
+    fail(std::string("Cannot both keep and split out function ") +
+         func.c_str());
+  }
+
+  return valid;
+}
+
+void WasmSplitOptions::parse(int argc, const char* argv[]) {
+  ToolOptions::parse(argc, argv);
+  // Since --quiet is defined in ToolOptions but --verbose is defined here,
+  // --quiet doesn't know to unset --verbose. Fix it up here.
+  if (quiet && verbose) {
+    verbose = false;
+  }
+}
+
+void parseInput(Module& wasm, const WasmSplitOptions& options) {
+  ModuleReader reader;
+  reader.setProfile(options.profile);
+  try {
+    reader.read(options.input, wasm);
+  } catch (ParseException& p) {
+    p.dump(std::cerr);
+    std::cerr << '\n';
+    Fatal() << "error parsing wasm";
+  } catch (std::bad_alloc&) {
+    Fatal() << "error building module, std::bad_alloc (possibly invalid "
+               "request for silly amounts of memory)";
+  }
+  options.applyFeatures(wasm);
+}
+
+// Add a global monotonic counter and a timestamp global for each function, code
+// at the beginning of each function to set its timestamp, and a new exported
+// function for dumping the profile data.
+struct Instrumenter : public Pass {
+  PassRunner* runner = nullptr;
+  Module* wasm = nullptr;
+
+  const std::string& profileExport;
+  uint64_t moduleHash;
+
+  Name counterGlobal;
+  std::vector<Name> functionGlobals;
+
+  Instrumenter(const std::string& profileExport, uint64_t moduleHash);
+
+  void run(PassRunner* runner, Module* wasm) override;
+  void addGlobals();
+  void instrumentFuncs();
+  void addProfileExport();
+};
+
+Instrumenter::Instrumenter(const std::string& profileExport,
+                           uint64_t moduleHash)
+  : profileExport(profileExport), moduleHash(moduleHash) {}
+
+void Instrumenter::run(PassRunner* runner, Module* wasm) {
+  this->runner = runner;
+  this->wasm = wasm;
+  addGlobals();
+  instrumentFuncs();
+  addProfileExport();
+}
+
+void Instrumenter::addGlobals() {
+  // Create fresh global names (over-reserves, but that's ok)
+  counterGlobal = Names::getValidGlobalName(*wasm, "monotonic_counter");
+  functionGlobals.reserve(wasm->functions.size());
+  ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
+    functionGlobals.push_back(Names::getValidGlobalName(
+      *wasm, std::string(func->name.c_str()) + "_timestamp"));
+  });
+
+  // Create and add new globals
+  auto addGlobal = [&](Name name) {
+    auto global = Builder::makeGlobal(
+      name,
+      Type::i32,
+      Builder(*wasm).makeConst(Literal::makeZero(Type::i32)),
+      Builder::Mutable);
+    global->hasExplicitName = true;
+    wasm->addGlobal(std::move(global));
+  };
+  addGlobal(counterGlobal);
+  for (auto& name : functionGlobals) {
+    addGlobal(name);
+  }
+}
+
+void Instrumenter::instrumentFuncs() {
+  // Inject the following code at the beginning of each function to advance the
+  // monotonic counter and set the function's timestamp if it hasn't already
+  // been set.
+  //
+  //   (if (i32.eqz (global.get $timestamp))
+  //     (block
+  //       (global.set $monotonic_counter
+  //         (i32.add
+  //           (global.get $monotonic_counter)
+  //           (i32.const 1)
+  //         )
+  //       )
+  //       (global.set $timestamp
+  //         (global.get $monotonic_counter)
+  //       )
+  //     )
+  //   )
+  Builder builder(*wasm);
+  auto globalIt = functionGlobals.begin();
+  ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
+    func->body = builder.makeSequence(
+      builder.makeIf(
+        builder.makeUnary(EqZInt32,
+                          builder.makeGlobalGet(*globalIt, Type::i32)),
+        builder.makeSequence(
+          builder.makeGlobalSet(
+            counterGlobal,
+            builder.makeBinary(AddInt32,
+                               builder.makeGlobalGet(counterGlobal, Type::i32),
+                               builder.makeConst(Literal::makeOne(Type::i32)))),
+          builder.makeGlobalSet(
+            *globalIt, builder.makeGlobalGet(counterGlobal, Type::i32)))),
+      func->body,
+      func->body->type);
+    ++globalIt;
+  });
+}
+
+// wasm-split profile format:
+//
+// The wasm-split profile is a binary format designed to be simple to produce
+// and consume. It is comprised of:
+//
+//   1. An 8-byte module hash
+//
+//   2. A 4-byte timestamp for each defined function
+//
+// The module hash is meant to guard against bugs where the module that was
+// instrumented and the module that is being split are different. The timestamps
+// are non-zero for functions that were called during the instrumented run and 0
+// otherwise. Functions with smaller non-zero timestamps were called earlier in
+// the instrumented run than funtions with larger timestamps.
+
+void Instrumenter::addProfileExport() {
+  // Create and export a function to dump the profile into a given memory
+  // buffer. The function takes the available address and buffer size as
+  // arguments and returns the total size of the profile. It only actually
+  // writes the profile if the given space is sufficient to hold it.
+  auto name = Names::getValidFunctionName(*wasm, profileExport);
+  auto writeProfile = Builder::makeFunction(
+    name, Signature({Type::i32, Type::i32}, Type::i32), {});
+  writeProfile->hasExplicitName = true;
+  writeProfile->setLocalName(0, "addr");
+  writeProfile->setLocalName(1, "size");
+
+  // Calculate the size of the profile:
+  //   8 bytes module hash +
+  //   4 bytes for the timestamp for each function
+  const size_t profileSize = 8 + 4 * functionGlobals.size();
+
+  // Create the function body
+  Builder builder(*wasm);
+  auto getAddr = [&]() { return builder.makeLocalGet(0, Type::i32); };
+  auto getSize = [&]() { return builder.makeLocalGet(1, Type::i32); };
+  auto hashConst = [&]() { return builder.makeConst(int64_t(moduleHash)); };
+  auto profileSizeConst = [&]() {
+    return builder.makeConst(int32_t(profileSize));
+  };
+
+  // Write the hash followed by all the time stamps
+  Expression* writeData =
+    builder.makeStore(8, 0, 1, getAddr(), hashConst(), Type::i64);
+
+  uint32_t offset = 8;
+  for (const auto& global : functionGlobals) {
+    writeData = builder.blockify(
+      writeData,
+      builder.makeStore(4,
+                        offset,
+                        1,
+                        getAddr(),
+                        builder.makeGlobalGet(global, Type::i32),
+                        Type::i32));
+    offset += 4;
+  }
+
+  writeProfile->body = builder.makeSequence(
+    builder.makeIf(builder.makeBinary(GeUInt32, getSize(), profileSizeConst()),
+                   writeData),
+    profileSizeConst());
+
+  // Create an export for the function
+  wasm->addFunction(std::move(writeProfile));
+  wasm->addExport(
+    Builder::makeExport(profileExport, name, ExternalKind::Function));
+
+  // Also make sure there is a memory with enough pages to write into
+  size_t pages = (profileSize + Memory::kPageSize - 1) / Memory::kPageSize;
+  if (!wasm->memory.exists) {
+    wasm->memory.exists = true;
+    wasm->memory.initial = pages;
+    wasm->memory.max = pages;
+  } else if (wasm->memory.initial < pages) {
+    wasm->memory.initial = pages;
+    if (wasm->memory.max < pages) {
+      wasm->memory.max = pages;
+    }
+  }
+
+  // TODO: export the memory if it is not already exported.
+}
+
+uint64_t hashFile(const std::string& filename) {
+  auto contents(read_file<std::vector<char>>(filename, Flags::Binary));
+  size_t digest = 0;
+  // Don't use `hash` or `rehash` - they aren't deterministic between executions
+  for (char c : contents) {
+    hash_combine(digest, c);
+  }
+  return uint64_t(digest);
+}
+
+void adjustTableSize(Module& wasm, int initialSize) {
+  if (initialSize < 0) {
+    return;
+  }
+  if (!wasm.table.exists) {
+    Fatal() << "--initial-table used but there is no table";
+  }
+  if ((uint64_t)initialSize < wasm.table.initial) {
+    Fatal() << "Specified initial table size too small, should be at least "
+            << wasm.table.initial;
+  }
+  if ((uint64_t)initialSize > wasm.table.max) {
+    Fatal() << "Specified initial table size larger than max table size "
+            << wasm.table.max;
+  }
+  wasm.table.initial = initialSize;
+}
+
+void instrumentModule(Module& wasm, const WasmSplitOptions& options) {
+  // Check that the profile export name is not already taken
+  if (wasm.getExportOrNull(options.profileExport) != nullptr) {
+    Fatal() << "error: Export " << options.profileExport << " already exists.";
+  }
+
+  uint64_t moduleHash = hashFile(options.input);
+  PassRunner runner(&wasm, options.passOptions);
+  Instrumenter(options.profileExport, moduleHash).run(&runner, &wasm);
+
+  adjustTableSize(wasm, options.initialTableSize);
+
+  // Write the output modules
+  ModuleWriter writer;
+  writer.setBinary(options.emitBinary);
+  writer.setDebugInfo(options.passOptions.debugInfo);
+  writer.write(wasm, options.output);
+}
+
+// See "wasm-split profile format" above for more information.
+std::set<Name> readProfile(Module& wasm, const WasmSplitOptions& options) {
+  auto profileData =
+    read_file<std::vector<char>>(options.profileFile, Flags::Binary);
+  size_t i = 0;
+  auto readi32 = [&]() {
+    if (i + 4 > profileData.size()) {
+      Fatal() << "Unexpected end of profile data";
+    }
+    uint32_t i32 = 0;
+    i32 |= uint32_t(uint8_t(profileData[i++]));
+    i32 |= uint32_t(uint8_t(profileData[i++])) << 8;
+    i32 |= uint32_t(uint8_t(profileData[i++])) << 16;
+    i32 |= uint32_t(uint8_t(profileData[i++])) << 24;
+    return i32;
+  };
+
+  // Read and compare the 8-byte module hash.
+  uint64_t expected = readi32();
+  expected |= uint64_t(readi32()) << 32;
+  if (expected != hashFile(options.input)) {
+    Fatal() << "error: checksum in profile does not match module checksum. "
+            << "The split module must be the original module that was "
+            << "instrumented to generate the profile.";
+  }
+
+  std::set<Name> keptFuncs;
+  ModuleUtils::iterDefinedFunctions(wasm, [&](Function* func) {
+    uint32_t timestamp = readi32();
+    // TODO: provide an option to set the timestamp threshold. For now, kee the
+    // function if the profile shows it being run at all.
+    if (timestamp > 0) {
+      keptFuncs.insert(func->name);
+    }
+  });
+
+  if (i != profileData.size()) {
+    // TODO: Handle concatenated profile data.
+    Fatal() << "Unexpected extra profile data";
+  }
+
+  return keptFuncs;
+}
+
+void splitModule(Module& wasm, const WasmSplitOptions& options) {
+  std::set<Name> keepFuncs;
+
+  if (options.profileFile.size()) {
+    // Use the profile to initialize `keepFuncs`
+    keepFuncs = readProfile(wasm, options);
+  }
+
+  // Add in the functions specified with --keep-funcs
+  for (auto& func : options.keepFuncs) {
+    if (!options.quiet && wasm.getFunctionOrNull(func) == nullptr) {
+      std::cerr << "warning: function " << func << " does not exist\n";
+    }
+    keepFuncs.insert(func);
+  }
+
+  // Remove the functions specified with --remove-funcs
+  for (auto& func : options.splitFuncs) {
+    auto* function = wasm.getFunctionOrNull(func);
+    if (!options.quiet && function == nullptr) {
+      std::cerr << "warning: function " << func << " does not exist\n";
+    }
+    if (function && function->imported()) {
+      if (!options.quiet) {
+        std::cerr << "warning: cannot split out imported function " << func
+                  << "\n";
+      }
+    } else {
+      keepFuncs.erase(func);
+    }
+  }
+
+  if (!options.quiet && keepFuncs.size() == 0) {
+    std::cerr << "warning: not keeping any functions in the primary module\n";
+  }
+
+  // If warnings are enabled, check that any functions are being split out.
+  if (!options.quiet) {
+    std::set<Name> splitFuncs;
+    ModuleUtils::iterDefinedFunctions(wasm, [&](Function* func) {
+      if (keepFuncs.count(func->name) == 0) {
+        splitFuncs.insert(func->name);
+      }
+    });
+
+    if (splitFuncs.size() == 0) {
+      std::cerr
+        << "warning: not splitting any functions out to the secondary module\n";
+    }
+
+    // Dump the kept and split functions if we are verbose
+    if (options.verbose) {
+      auto printCommaSeparated = [&](auto funcs) {
+        for (auto it = funcs.begin(); it != funcs.end(); ++it) {
+          if (it != funcs.begin()) {
+            std::cout << ", ";
+          }
+          std::cout << *it;
+        }
+      };
+
+      std::cout << "Keeping functions: ";
+      printCommaSeparated(keepFuncs);
+      std::cout << "\n";
+
+      std::cout << "Splitting out functions: ";
+      printCommaSeparated(splitFuncs);
+      std::cout << "\n";
+    }
+  }
+
+  // Actually perform the splitting
+  ModuleSplitting::Config config;
+  config.primaryFuncs = std::move(keepFuncs);
+  if (options.importNamespace.size()) {
+    config.importNamespace = options.importNamespace;
+  }
+  if (options.placeholderNamespace.size()) {
+    config.placeholderNamespace = options.placeholderNamespace;
+  }
+  if (options.exportPrefix.size()) {
+    config.newExportPrefix = options.exportPrefix;
+  }
+  std::unique_ptr<Module> secondary =
+    ModuleSplitting::splitFunctions(wasm, config);
+
+  adjustTableSize(wasm, options.initialTableSize);
+  adjustTableSize(*secondary, options.initialTableSize);
+
+  // Write the output modules
+  ModuleWriter writer;
+  writer.setBinary(options.emitBinary);
+  writer.setDebugInfo(options.passOptions.debugInfo);
+  writer.write(wasm, options.primaryOutput);
+  writer.write(*secondary, options.secondaryOutput);
+}
+
+} // anonymous namespace
+
+int main(int argc, const char* argv[]) {
+  WasmSplitOptions options;
+  options.parse(argc, argv);
+
+  if (!options.validate()) {
+    Fatal() << "Invalid command line arguments";
+  }
+
+  Module wasm;
+  parseInput(wasm, options);
+
+  if (options.passOptions.validate && !WasmValidator().validate(wasm)) {
+    Fatal() << "error validating input";
+  }
+
+  if (options.instrument) {
+    instrumentModule(wasm, options);
+  } else {
+    splitModule(wasm, options);
+  }
+}
diff --git a/binaryen/src/tools/wasm2c-wrapper.h b/binaryen/src/tools/wasm2c-wrapper.h
--- a/binaryen/src/tools/wasm2c-wrapper.h
+++ b/binaryen/src/tools/wasm2c-wrapper.h
@@ -25,6 +25,58 @@
 
 namespace wasm {
 
+// Mangle a name in (hopefully) exactly the same way wasm2c does.
+static std::string wasm2cMangle(Name name, Signature sig) {
+  const char escapePrefix = 'Z';
+  std::string mangled = "Z_";
+  const char* original = name.str;
+  unsigned char c;
+  while ((c = *original++)) {
+    if ((isalnum(c) && c != escapePrefix) || c == '_') {
+      // This character is ok to emit as it is.
+      mangled += c;
+    } else {
+      // This must be escaped, as prefix + hex character code.
+      mangled += escapePrefix;
+      std::stringstream ss;
+      ss << std::hex << std::uppercase << unsigned(c);
+      mangled += ss.str();
+    }
+  }
+
+  // Emit the result and params.
+  mangled += "Z_";
+
+  auto wasm2cSignature = [](Type type) {
+    TODO_SINGLE_COMPOUND(type);
+    switch (type.getBasic()) {
+      case Type::none:
+        return 'v';
+      case Type::i32:
+        return 'i';
+      case Type::i64:
+        return 'j';
+      case Type::f32:
+        return 'f';
+      case Type::f64:
+        return 'd';
+      default:
+        Fatal() << "unhandled wasm2c wrapper signature type: " << type;
+    }
+  };
+
+  mangled += wasm2cSignature(sig.results);
+  if (sig.params.isTuple()) {
+    for (const auto& param : sig.params) {
+      mangled += wasm2cSignature(param);
+    }
+  } else {
+    mangled += wasm2cSignature(sig.params);
+  }
+
+  return mangled;
+}
+
 static std::string generateWasm2CWrapper(Module& wasm) {
   // First, emit implementations of the wasm's imports so that the wasm2c code
   // can call them. The names use wasm2c's name mangling.
@@ -142,35 +194,12 @@
       }
     }
 
-    // Emit the callee's name with wasm2c name mangling.
-    ret += std::string("(*Z_") + exp->name.str + "Z_";
+    // Call the export.
+    ret += "(*";
 
-    auto wasm2cSignature = [](Type type) {
-      TODO_SINGLE_COMPOUND(type);
-      switch (type.getBasic()) {
-        case Type::none:
-          return 'v';
-        case Type::i32:
-          return 'i';
-        case Type::i64:
-          return 'j';
-        case Type::f32:
-          return 'f';
-        case Type::f64:
-          return 'd';
-        default:
-          Fatal() << "unhandled wasm2c wrapper signature type: " << type;
-      }
-    };
+    // Emit the callee's name with wasm2c name mangling.
+    ret += wasm2cMangle(exp->name, func->sig);
 
-    ret += wasm2cSignature(result);
-    if (func->sig.params.isTuple()) {
-      for (const auto& param : func->sig.params) {
-        ret += wasm2cSignature(param);
-      }
-    } else {
-      ret += wasm2cSignature(func->sig.params);
-    }
     ret += ")(";
 
     // Emit the parameters (all 0s, like the other wrappers).
diff --git a/binaryen/src/tools/wasm2js.cpp b/binaryen/src/tools/wasm2js.cpp
--- a/binaryen/src/tools/wasm2js.cpp
+++ b/binaryen/src/tools/wasm2js.cpp
@@ -984,7 +984,7 @@
 
   if (options.passOptions.validate) {
     if (!WasmValidator().validate(wasm)) {
-      WasmPrinter::printModule(&wasm);
+      std::cout << wasm << '\n';
       Fatal() << "error in validating input";
     }
   }
diff --git a/binaryen/src/wasm-binary.h b/binaryen/src/wasm-binary.h
--- a/binaryen/src/wasm-binary.h
+++ b/binaryen/src/wasm-binary.h
@@ -25,8 +25,6 @@
 #include <ostream>
 #include <type_traits>
 
-#include "asm_v_wasm.h"
-#include "asmjs/shared-constants.h"
 #include "ir/import-utils.h"
 #include "ir/module-utils.h"
 #include "parsing.h"
@@ -340,6 +338,8 @@
   f32 = -0x3,  // 0x7d
   f64 = -0x4,  // 0x7c
   v128 = -0x5, // 0x7b
+  i8 = -0x6,   // 0x7a
+  i16 = -0x7,  // 0x79
   // function reference type
   funcref = -0x10, // 0x70
   // opaque host reference type
@@ -348,12 +348,22 @@
   anyref = -0x12, // 0x6e
   // comparable reference type
   eqref = -0x13, // 0x6d
+  // nullable typed function reference type, with parameter
+  nullable = -0x14, // 0x6c
+  // non-nullable typed function reference type, with parameter
+  nonnullable = -0x15, // 0x6b
   // integer reference type
   i31ref = -0x16, // 0x6a
-  // exception reference type
-  exnref = -0x18, // 0x68
+  // run-time type info type, with depth index n
+  rtt_n = -0x17, // 0x69
+  // run-time type info type, without depth index n
+  rtt = -0x18, // 0x68
+  // exception reference type TODO remove; the code for now is incorrect
+  exnref = -0x19, // 0x67
   // func_type form
-  Func = -0x20, // 0x60
+  Func = -0x20,   // 0x60
+  Struct = -0x21, // 0x5f
+  Array = -0x22,  // 0x5e
   // block_type
   Empty = -0x40 // 0x40
 };
@@ -388,6 +398,7 @@
 extern const char* MultivalueFeature;
 extern const char* GCFeature;
 extern const char* Memory64Feature;
+extern const char* TypedFunctionReferencesFeature;
 
 enum Subsection {
   NameModule = 0,
@@ -771,6 +782,7 @@
   I32x4LeU = 0x3e,
   I32x4GeS = 0x3f,
   I32x4GeU = 0x40,
+  I64x2Eq = 0xc0,
   F32x4Eq = 0x41,
   F32x4Ne = 0x42,
   F32x4Lt = 0x43,
@@ -791,6 +803,20 @@
   V128Xor = 0x51,
   V128Bitselect = 0x52,
 
+  V8x16SignSelect = 0x7d,
+  V16x8SignSelect = 0x7e,
+  V32x4SignSelect = 0x7f,
+  V64x2SignSelect = 0x94,
+
+  V128Load8Lane = 0x58,
+  V128Load16Lane = 0x59,
+  V128Load32Lane = 0x5a,
+  V128Load64Lane = 0x5b,
+  V128Store8Lane = 0x5c,
+  V128Store16Lane = 0x5d,
+  V128Store32Lane = 0x5e,
+  V128Store64Lane = 0x5f,
+
   I8x16Abs = 0x60,
   I8x16Neg = 0x61,
   I8x16AnyTrue = 0x62,
@@ -814,6 +840,8 @@
   I8x16MaxU = 0x79,
   I8x16AvgrU = 0x7b,
 
+  I8x16Popcnt = 0x7c,
+
   I16x8Abs = 0x80,
   I16x8Neg = 0x81,
   I16x8AnyTrue = 0x82,
@@ -840,6 +868,7 @@
   I16x8MaxS = 0x98,
   I16x8MaxU = 0x99,
   I16x8AvgrU = 0x9b,
+  I16x8Q15MulrSatS = 0x9c,
 
   I32x4Abs = 0xa0,
   I32x4Neg = 0xa1,
@@ -862,9 +891,12 @@
   I32x4MaxU = 0xb9,
   I32x4DotSVecI16x8 = 0xba,
 
+  I64x2Bitmask = 0xc4,
+  I64x2WidenLowSI32x4 = 0xc7,
+  I64x2WidenHighSI32x4 = 0xc8,
+  I64x2WidenLowUI32x4 = 0xc9,
+  I64x2WidenHighUI32x4 = 0xca,
   I64x2Neg = 0xc1,
-  I64x2AnyTrue = 0xc2,
-  I64x2AllTrue = 0xc3,
   I64x2Shl = 0xcb,
   I64x2ShrS = 0xcc,
   I64x2ShrU = 0xcd,
@@ -905,6 +937,11 @@
   F64x2PMin = 0xf6,
   F64x2PMax = 0xf7,
 
+  I16x8ExtAddPairWiseSI8x16 = 0xc2,
+  I16x8ExtAddPairWiseUI8x16 = 0xc3,
+  I32x4ExtAddPairWiseSI16x8 = 0xa5,
+  I32x4ExtAddPairWiseUI16x8 = 0xa6,
+
   I32x4TruncSatSF32x4 = 0xf8,
   I32x4TruncSatUF32x4 = 0xf9,
   F32x4ConvertSI32x4 = 0xfa,
@@ -923,6 +960,24 @@
   F64x2ConvertSI64x2 = 0x0102,
   F64x2ConvertUI64x2 = 0x0103,
 
+  I16x8ExtMulLowSI8x16 = 0x9a,
+  I16x8ExtMulHighSI8x16 = 0x9d,
+  I16x8ExtMulLowUI8x16 = 0x9e,
+  I16x8ExtMulHighUI8x16 = 0x9f,
+  I32x4ExtMulLowSI16x8 = 0xbb,
+  I32x4ExtMulHighSI16x8 = 0xbd,
+  I32x4ExtMulLowUI16x8 = 0xbe,
+  I32x4ExtMulHighUI16x8 = 0xbf,
+  I64x2ExtMulLowSI32x4 = 0xd2,
+  I64x2ExtMulHighSI32x4 = 0xd3,
+  I64x2ExtMulLowUI32x4 = 0xd6,
+  I64x2ExtMulHighUI32x4 = 0xd7,
+
+  // prefetch opcodes
+
+  PrefetchT = 0xc5,
+  PrefetchNT = 0xc6,
+
   // bulk memory opcodes
 
   MemoryInit = 0x08,
@@ -944,6 +999,11 @@
   Rethrow = 0x09,
   BrOnExn = 0x0a,
 
+  // typed function references opcodes
+
+  CallRef = 0x14,
+  RetCallRef = 0x15,
+
   // gc opcodes
 
   RefEq = 0xd5,
@@ -986,82 +1046,6 @@
 
 } // namespace BinaryConsts
 
-inline S32LEB binaryType(Type type) {
-  int ret = 0;
-  TODO_SINGLE_COMPOUND(type);
-  switch (type.getBasic()) {
-    // None only used for block signatures. TODO: Separate out?
-    case Type::none:
-      ret = BinaryConsts::EncodedType::Empty;
-      break;
-    case Type::i32:
-      ret = BinaryConsts::EncodedType::i32;
-      break;
-    case Type::i64:
-      ret = BinaryConsts::EncodedType::i64;
-      break;
-    case Type::f32:
-      ret = BinaryConsts::EncodedType::f32;
-      break;
-    case Type::f64:
-      ret = BinaryConsts::EncodedType::f64;
-      break;
-    case Type::v128:
-      ret = BinaryConsts::EncodedType::v128;
-      break;
-    case Type::funcref:
-      ret = BinaryConsts::EncodedType::funcref;
-      break;
-    case Type::externref:
-      ret = BinaryConsts::EncodedType::externref;
-      break;
-    case Type::exnref:
-      ret = BinaryConsts::EncodedType::exnref;
-      break;
-    case Type::anyref:
-      ret = BinaryConsts::EncodedType::anyref;
-      break;
-    case Type::eqref:
-      ret = BinaryConsts::EncodedType::eqref;
-      break;
-    case Type::i31ref:
-      ret = BinaryConsts::EncodedType::i31ref;
-      break;
-    case Type::unreachable:
-      WASM_UNREACHABLE("unexpected type");
-  }
-  return S32LEB(ret);
-}
-
-inline S32LEB binaryHeapType(HeapType type) {
-  int ret = 0;
-  switch (type.kind) {
-    case HeapType::FuncKind:
-      ret = BinaryConsts::EncodedHeapType::func;
-      break;
-    case HeapType::ExternKind:
-      ret = BinaryConsts::EncodedHeapType::extern_;
-      break;
-    case HeapType::ExnKind:
-      ret = BinaryConsts::EncodedHeapType::exn;
-      break;
-    case HeapType::AnyKind:
-      ret = BinaryConsts::EncodedHeapType::any;
-      break;
-    case HeapType::EqKind:
-      ret = BinaryConsts::EncodedHeapType::eq;
-      break;
-    case HeapType::I31Kind:
-      ret = BinaryConsts::EncodedHeapType::i31;
-      break;
-    case HeapType::SignatureKind:
-    case HeapType::StructKind:
-    case HeapType::ArrayKind:
-      WASM_UNREACHABLE("TODO: compound GC types");
-  }
-  return S32LEB(ret); // TODO: Actually encoded as s33
-}
-
 // Writes out wasm to the binary format
 
 class WasmBinaryWriter {
@@ -1168,7 +1152,7 @@
   uint32_t getFunctionIndex(Name name) const;
   uint32_t getGlobalIndex(Name name) const;
   uint32_t getEventIndex(Name name) const;
-  uint32_t getTypeIndex(Signature sig) const;
+  uint32_t getTypeIndex(HeapType type) const;
 
   void writeFunctionTableDeclaration();
   void writeTableElements();
@@ -1211,12 +1195,16 @@
 
   Module* getModule() { return wasm; }
 
+  void writeType(Type type);
+  void writeHeapType(HeapType type);
+  void writeField(const Field& field);
+
 private:
   Module* wasm;
   BufferWithRandomAccess& o;
   BinaryIndexes indexes;
-  std::unordered_map<Signature, Index> typeIndices;
-  std::vector<Signature> types;
+  std::unordered_map<HeapType, Index> typeIndices;
+  std::vector<HeapType> types;
 
   bool debugInfo = true;
   std::ostream* sourceMap = nullptr;
@@ -1260,8 +1248,8 @@
 
   std::set<BinaryConsts::Section> seenSections;
 
-  // All signatures present in the type section
-  std::vector<Signature> signatures;
+  // All types defined in the type section
+  std::vector<HeapType> types;
 
 public:
   WasmBinaryBuilder(Module& wasm, const std::vector<char>& input)
@@ -1288,19 +1276,26 @@
   uint64_t getU64LEB();
   int32_t getS32LEB();
   int64_t getS64LEB();
+  uint64_t getUPtrLEB();
+
+  // Read a value and get a type for it.
   Type getType();
+  // Get a type given the initial S32LEB has already been read, and is provided.
+  Type getType(int initial);
+
   HeapType getHeapType();
+  Mutability getMutability();
+  Field getField();
   Type getConcreteType();
   Name getInlineString();
   void verifyInt8(int8_t x);
   void verifyInt16(int16_t x);
   void verifyInt32(int32_t x);
   void verifyInt64(int64_t x);
-  void ungetInt8();
   void readHeader();
   void readStart();
   void readMemory();
-  void readSignatures();
+  void readTypes();
 
   // gets a name in the combined import+defined space
   Name getFunctionName(Index index);
@@ -1318,6 +1313,9 @@
   std::vector<Signature> functionSignatures;
 
   void readFunctionSignatures();
+  Signature getSignatureByFunctionIndex(Index index);
+  Signature getSignatureByTypeIndex(Index index);
+
   size_t nextLabel;
 
   Name getNextLabel();
@@ -1338,7 +1336,7 @@
   Index endOfFunction = -1;
 
   // we store globals here before wasm.addGlobal after we know their names
-  std::vector<Global*> globals;
+  std::vector<std::unique_ptr<Global>> globals;
   // we store global imports here before wasm.addGlobalImport after we know
   // their names
   std::vector<Global*> globalImports;
@@ -1451,19 +1449,20 @@
   // Gets a block of expressions. If it's just one, return that singleton.
   Expression* getBlockOrSingleton(Type type);
 
+  BreakTarget getBreakTarget(int32_t offset);
+
+  void readMemoryAccess(Address& alignment, Address& offset);
+
   void visitIf(If* curr);
   void visitLoop(Loop* curr);
-  BreakTarget getBreakTarget(int32_t offset);
   void visitBreak(Break* curr, uint8_t code);
   void visitSwitch(Switch* curr);
-
   void visitCall(Call* curr);
   void visitCallIndirect(CallIndirect* curr);
   void visitLocalGet(LocalGet* curr);
   void visitLocalSet(LocalSet* curr, uint8_t code);
   void visitGlobalGet(GlobalGet* curr);
   void visitGlobalSet(GlobalSet* curr);
-  void readMemoryAccess(Address& alignment, Address& offset);
   bool maybeVisitLoad(Expression*& out, uint8_t code, bool isAtomic);
   bool maybeVisitStore(Expression*& out, uint8_t code, bool isAtomic);
   bool maybeVisitNontrappingTrunc(Expression*& out, uint32_t code);
@@ -1486,6 +1485,8 @@
   bool maybeVisitSIMDTernary(Expression*& out, uint32_t code);
   bool maybeVisitSIMDShift(Expression*& out, uint32_t code);
   bool maybeVisitSIMDLoad(Expression*& out, uint32_t code);
+  bool maybeVisitSIMDLoadStoreLane(Expression*& out, uint32_t code);
+  bool maybeVisitPrefetch(Expression*& out, uint32_t code);
   bool maybeVisitMemoryInit(Expression*& out, uint32_t code);
   bool maybeVisitDataDrop(Expression*& out, uint32_t code);
   bool maybeVisitMemoryCopy(Expression*& out, uint32_t code);
@@ -1519,8 +1520,16 @@
   void visitThrow(Throw* curr);
   void visitRethrow(Rethrow* curr);
   void visitBrOnExn(BrOnExn* curr);
+  void visitCallRef(CallRef* curr);
 
   void throwError(std::string text);
+
+  // Struct/Array instructions have an unnecessary heap type that is just for
+  // validation (except for the case of unreachability, but that's not a problem
+  // anyhow, we can ignore it there). That is, we also have a reference / rtt
+  // child from which we can infer the type anyhow, and we just need to check
+  // that type is the same.
+  void validateHeapTypeUsingChild(Expression* child, HeapType heapType);
 
 private:
   bool hasDWARFSections();
diff --git a/binaryen/src/wasm-builder.h b/binaryen/src/wasm-builder.h
--- a/binaryen/src/wasm-builder.h
+++ b/binaryen/src/wasm-builder.h
@@ -41,11 +41,11 @@
 
   // make* functions, other globals
 
-  Function* makeFunction(Name name,
-                         Signature sig,
-                         std::vector<Type>&& vars,
-                         Expression* body = nullptr) {
-    auto* func = new Function;
+  static std::unique_ptr<Function> makeFunction(Name name,
+                                                Signature sig,
+                                                std::vector<Type>&& vars,
+                                                Expression* body = nullptr) {
+    auto func = std::make_unique<Function>();
     func->name = name;
     func->sig = sig;
     func->body = body;
@@ -53,12 +53,12 @@
     return func;
   }
 
-  Function* makeFunction(Name name,
-                         std::vector<NameType>&& params,
-                         Type resultType,
-                         std::vector<NameType>&& vars,
-                         Expression* body = nullptr) {
-    auto* func = new Function;
+  static std::unique_ptr<Function> makeFunction(Name name,
+                                                std::vector<NameType>&& params,
+                                                Type resultType,
+                                                std::vector<NameType>&& vars,
+                                                Expression* body = nullptr) {
+    auto func = std::make_unique<Function>();
     func->name = name;
     func->body = body;
     std::vector<Type> paramVec;
@@ -78,14 +78,36 @@
     return func;
   }
 
-  Export* makeExport(Name name, Name value, ExternalKind kind) {
-    auto* export_ = new Export();
+  static std::unique_ptr<Export>
+  makeExport(Name name, Name value, ExternalKind kind) {
+    auto export_ = std::make_unique<Export>();
     export_->name = name;
     export_->value = value;
     export_->kind = kind;
     return export_;
   }
 
+  enum Mutability { Mutable, Immutable };
+
+  static std::unique_ptr<Global>
+  makeGlobal(Name name, Type type, Expression* init, Mutability mutable_) {
+    auto glob = std::make_unique<Global>();
+    glob->name = name;
+    glob->type = type;
+    glob->init = init;
+    glob->mutable_ = mutable_ == Mutable;
+    return glob;
+  }
+
+  static std::unique_ptr<Event>
+  makeEvent(Name name, uint32_t attribute, Signature sig) {
+    auto event = std::make_unique<Event>();
+    event->name = name;
+    event->attribute = attribute;
+    event->sig = sig;
+    return event;
+  }
+
   // IR nodes
 
   Nop* makeNop() { return wasm.allocator.alloc<Nop>(); }
@@ -221,8 +243,9 @@
     call->finalize();
     return call;
   }
+  template<typename T>
   CallIndirect* makeCallIndirect(Expression* target,
-                                 const std::vector<Expression*>& args,
+                                 const T& args,
                                  Signature sig,
                                  bool isReturn = false) {
     auto* call = wasm.allocator.alloc<CallIndirect>();
@@ -234,6 +257,19 @@
     call->finalize();
     return call;
   }
+  template<typename T>
+  CallRef* makeCallRef(Expression* target,
+                       const T& args,
+                       Type type,
+                       bool isReturn = false) {
+    auto* call = wasm.allocator.alloc<CallRef>();
+    call->type = type;
+    call->target = target;
+    call->operands.set(args);
+    call->isReturn = isReturn;
+    call->finalize();
+    return call;
+  }
   LocalGet* makeLocalGet(Index index, Type type) {
     auto* ret = wasm.allocator.alloc<LocalGet>();
     ret->index = index;
@@ -434,6 +470,32 @@
     ret->finalize();
     return ret;
   }
+  SIMDLoadStoreLane* makeSIMDLoadStoreLane(SIMDLoadStoreLaneOp op,
+                                           Address offset,
+                                           Address align,
+                                           uint8_t index,
+                                           Expression* ptr,
+                                           Expression* vec) {
+    auto* ret = wasm.allocator.alloc<SIMDLoadStoreLane>();
+    ret->op = op;
+    ret->offset = offset;
+    ret->align = align;
+    ret->index = index;
+    ret->ptr = ptr;
+    ret->vec = vec;
+    ret->finalize();
+    return ret;
+  }
+  Prefetch*
+  makePrefetch(PrefetchOp op, Address offset, Address align, Expression* ptr) {
+    auto* ret = wasm.allocator.alloc<Prefetch>();
+    ret->op = op;
+    ret->offset = offset;
+    ret->align = align;
+    ret->ptr = ptr;
+    ret->finalize();
+    return ret;
+  }
   MemoryInit* makeMemoryInit(uint32_t segment,
                              Expression* dest,
                              Expression* offset,
@@ -549,10 +611,10 @@
     ret->finalize();
     return ret;
   }
-  RefFunc* makeRefFunc(Name func) {
+  RefFunc* makeRefFunc(Name func, Type type) {
     auto* ret = wasm.allocator.alloc<RefFunc>();
     ret->func = func;
-    ret->finalize();
+    ret->finalize(type);
     return ret;
   }
   RefEq* makeRefEq(Expression* left, Expression* right) {
@@ -639,75 +701,104 @@
     ret->finalize();
     return ret;
   }
-  RefTest* makeRefTest() {
+  RefTest* makeRefTest(Expression* ref, Expression* rtt) {
     auto* ret = wasm.allocator.alloc<RefTest>();
-    WASM_UNREACHABLE("TODO (gc): ref.test");
+    ret->ref = ref;
+    ret->rtt = rtt;
     ret->finalize();
     return ret;
   }
-  RefCast* makeRefCast() {
+  RefCast* makeRefCast(Expression* ref, Expression* rtt) {
     auto* ret = wasm.allocator.alloc<RefCast>();
-    WASM_UNREACHABLE("TODO (gc): ref.cast");
+    ret->ref = ref;
+    ret->rtt = rtt;
     ret->finalize();
     return ret;
   }
-  BrOnCast* makeBrOnCast() {
+  BrOnCast*
+  makeBrOnCast(Name name, HeapType heapType, Expression* ref, Expression* rtt) {
     auto* ret = wasm.allocator.alloc<BrOnCast>();
-    WASM_UNREACHABLE("TODO (gc): br_on_cast");
+    ret->name = name;
+    ret->castType = Type(heapType, Nullable);
+    ret->ref = ref;
+    ret->rtt = rtt;
     ret->finalize();
     return ret;
   }
-  RttCanon* makeRttCanon() {
+  RttCanon* makeRttCanon(HeapType heapType) {
     auto* ret = wasm.allocator.alloc<RttCanon>();
-    WASM_UNREACHABLE("TODO (gc): rtt.canon");
+    ret->type = Type(Rtt(0, heapType));
     ret->finalize();
     return ret;
   }
-  RttSub* makeRttSub() {
+  RttSub* makeRttSub(HeapType heapType, Expression* parent) {
     auto* ret = wasm.allocator.alloc<RttSub>();
-    WASM_UNREACHABLE("TODO (gc): rtt.sub");
+    ret->parent = parent;
+    auto parentRtt = parent->type.getRtt();
+    if (parentRtt.hasDepth()) {
+      ret->type = Type(Rtt(parentRtt.depth + 1, heapType));
+    } else {
+      ret->type = Type(Rtt(heapType));
+    }
     ret->finalize();
     return ret;
   }
-  StructNew* makeStructNew() {
+  template<typename T>
+  StructNew* makeStructNew(Expression* rtt, const T& args) {
     auto* ret = wasm.allocator.alloc<StructNew>();
-    WASM_UNREACHABLE("TODO (gc): struct.new");
+    ret->rtt = rtt;
+    ret->operands.set(args);
     ret->finalize();
     return ret;
   }
-  StructGet* makeStructGet() {
+  StructGet*
+  makeStructGet(Index index, Expression* ref, Type type, bool signed_ = false) {
     auto* ret = wasm.allocator.alloc<StructGet>();
-    WASM_UNREACHABLE("TODO (gc): struct.get");
+    ret->index = index;
+    ret->ref = ref;
+    ret->type = type;
+    ret->signed_ = signed_;
     ret->finalize();
     return ret;
   }
-  StructSet* makeStructSet() {
+  StructSet* makeStructSet(Index index, Expression* ref, Expression* value) {
     auto* ret = wasm.allocator.alloc<StructSet>();
-    WASM_UNREACHABLE("TODO (gc): struct.set");
+    ret->index = index;
+    ret->ref = ref;
+    ret->value = value;
     ret->finalize();
     return ret;
   }
-  ArrayNew* makeArrayNew() {
+  ArrayNew*
+  makeArrayNew(Expression* rtt, Expression* size, Expression* init = nullptr) {
     auto* ret = wasm.allocator.alloc<ArrayNew>();
-    WASM_UNREACHABLE("TODO (gc): array.new");
+    ret->rtt = rtt;
+    ret->size = size;
+    ret->init = init;
     ret->finalize();
     return ret;
   }
-  ArrayGet* makeArrayGet() {
+  ArrayGet*
+  makeArrayGet(Expression* ref, Expression* index, bool signed_ = false) {
     auto* ret = wasm.allocator.alloc<ArrayGet>();
-    WASM_UNREACHABLE("TODO (gc): array.get");
+    ret->ref = ref;
+    ret->index = index;
+    ret->signed_ = signed_;
     ret->finalize();
     return ret;
   }
-  ArraySet* makeArraySet() {
+  ArraySet*
+  makeArraySet(Expression* ref, Expression* index, Expression* value) {
     auto* ret = wasm.allocator.alloc<ArraySet>();
-    WASM_UNREACHABLE("TODO (gc): array.set");
+    ret->ref = ref;
+    ret->index = index;
+    ret->value = value;
     ret->finalize();
     return ret;
   }
-  ArrayLen* makeArrayLen() {
+  ArrayLen* makeArrayLen(Expression* ref) {
     auto* ret = wasm.allocator.alloc<ArrayLen>();
-    WASM_UNREACHABLE("TODO (gc): array.len");
+    ret->ref = ref;
     ret->finalize();
     return ret;
   }
@@ -724,24 +815,28 @@
   // Make a constant expression. This might be a wasm Const, or something
   // else of constant value like ref.null.
   Expression* makeConstantExpression(Literal value) {
-    TODO_SINGLE_COMPOUND(value.type);
-    switch (value.type.getBasic()) {
-      case Type::funcref:
-        if (!value.isNull()) {
-          return makeRefFunc(value.getFunc());
-        }
-        return makeRefNull(value.type);
+    auto type = value.type;
+    if (type.isNumber()) {
+      return makeConst(value);
+    }
+    if (value.isNull()) {
+      return makeRefNull(type);
+    }
+    if (type.isFunction()) {
+      return makeRefFunc(value.getFunc(), type);
+    }
+    TODO_SINGLE_COMPOUND(type);
+    switch (type.getBasic()) {
       case Type::externref:
       case Type::exnref: // TODO: ExceptionPackage?
       case Type::anyref:
       case Type::eqref:
         assert(value.isNull() && "unexpected non-null reference type literal");
-        return makeRefNull(value.type);
+        return makeRefNull(type);
       case Type::i31ref:
         return makeI31New(makeConst(value.geti31()));
       default:
-        assert(value.type.isNumber());
-        return makeConst(value);
+        WASM_UNREACHABLE("invalid constant expression");
     }
   }
 
@@ -906,6 +1001,13 @@
     if (curr->type.isTuple()) {
       return makeConstantExpression(Literal::makeZeros(curr->type));
     }
+    if (curr->type.isNullable()) {
+      return ExpressionManipulator::refNull(curr, curr->type);
+    }
+    if (curr->type.isFunction()) {
+      // We can't do any better, keep the original.
+      return curr;
+    }
     Literal value;
     // TODO: reuse node conditionally when possible for literals
     TODO_SINGLE_COMPOUND(curr->type);
@@ -929,6 +1031,7 @@
         break;
       }
       case Type::funcref:
+        WASM_UNREACHABLE("handled above");
       case Type::externref:
       case Type::exnref:
       case Type::anyref:
@@ -942,28 +1045,6 @@
         return ExpressionManipulator::unreachable(curr);
     }
     return makeConst(value);
-  }
-
-  // Module-level helpers
-
-  enum Mutability { Mutable, Immutable };
-
-  static Global*
-  makeGlobal(Name name, Type type, Expression* init, Mutability mutable_) {
-    auto* glob = new Global;
-    glob->name = name;
-    glob->type = type;
-    glob->init = init;
-    glob->mutable_ = mutable_ == Mutable;
-    return glob;
-  }
-
-  static Event* makeEvent(Name name, uint32_t attribute, Signature sig) {
-    auto* event = new Event;
-    event->name = name;
-    event->attribute = attribute;
-    event->sig = sig;
-    return event;
   }
 };
 
diff --git a/binaryen/src/wasm-delegations-fields.h b/binaryen/src/wasm-delegations-fields.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-delegations-fields.h
@@ -0,0 +1,674 @@
+/*
+ * 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.
+ */
+
+// Implements a switch on an expression class ID, and has a case for each id
+// in which it runs delegates on the fields and immediates. You should include
+// this file after defining the relevant DELEGATE_* macros.
+//
+// All defines used here are undefed automatically at the end for you.
+//
+// Most of the defines are necessary, and you will get an error if you forget
+// them, but some are optional and some imply others, see below.
+//
+// The defines are as follows:
+//
+// DELEGATE_START(id) - called at the start of a case for an expression class.
+//
+// DELEGATE_END(id) - called at the end of a case.
+//
+// DELEGATE_GET_FIELD(id, name) - called to get a field by its name. This must
+//    know the object on which to get it, so it is just useful for the case
+//    where you operate on a single such object, but in that case it is nice
+//    because then other things can be defined automatically for you, see later.
+//
+// DELEGATE_FIELD_CHILD(id, name) - called for each child field (note: children
+//    are visited in reverse order, which is convenient for walking by pushing
+//    them to a stack first).
+//
+// DELEGATE_FIELD_OPTIONAL_CHILD(id, name) - called for a child that may not be
+//    present (like a Return's value). If you do not define this then
+//    DELEGATE_FIELD_CHILD is called.
+//
+// DELEGATE_FIELD_CHILD_VECTOR(id, name) - called for a variable-sized vector of
+//    child pointers. If this is not defined, and DELEGATE_GET_FIELD is, then
+//    DELEGATE_FIELD_CHILD is called on them.
+//
+// DELEGATE_FIELD_INT(id, name) - called for an integer field (bool, enum,
+//    Index, int32, or int64).
+//
+// DELEGATE_FIELD_INT_ARRAY(id, name) - called for a std::array of fixed size of
+//    integer values (like a SIMD mask). If this is not defined, and
+//    DELEGATE_GET_FIELD is, then DELEGATE_FIELD_INT is called on them.
+//
+// DELEGATE_FIELD_LITERAL(id, name) - called for a Literal.
+//
+// DELEGATE_FIELD_NAME(id, name) - called for a Name.
+//
+// DELEGATE_FIELD_SCOPE_NAME_DEF(id, name) - called for a scope name definition
+//    (like a block's name).
+//
+// DELEGATE_FIELD_SCOPE_NAME_USE(id, name) - called for a scope name use (like
+//    a break's target).
+//
+// DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name) - called for a variable-sized
+//    vector of scope names (like a switch's targets). If this is not defined,
+//    and DELEGATE_GET_FIELD is, then DELEGATE_FIELD_SCOPE_NAME_USE is called on
+//    them.
+//
+// DELEGATE_FIELD_SIGNATURE(id, name) - called for a Signature.
+//
+// DELEGATE_FIELD_TYPE(id, name) - called for a Type.
+//
+// DELEGATE_FIELD_ADDRESS(id, name) - called for an Address.
+
+#ifndef DELEGATE_START
+#define DELEGATE_START(id)
+#endif
+
+#ifndef DELEGATE_END
+#define DELEGATE_END(id)
+#endif
+
+#ifndef DELEGATE_FIELD_CHILD
+#error please define DELEGATE_FIELD_CHILD(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_OPTIONAL_CHILD
+#define DELEGATE_FIELD_OPTIONAL_CHILD(id, name) DELEGATE_FIELD_CHILD(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_CHILD_VECTOR
+#ifdef DELEGATE_GET_FIELD
+#define DELEGATE_FIELD_CHILD_VECTOR(id, name)                                  \
+  for (int i = int((DELEGATE_GET_FIELD(id, name)).size()) - 1; i >= 0; i--) {  \
+    DELEGATE_FIELD_CHILD(id, name[i]);                                         \
+  }
+#else
+#error please define DELEGATE_FIELD_CHILD_VECTOR(id, name)
+#endif
+#endif
+
+#ifndef DELEGATE_FIELD_INT
+#error please define DELEGATE_FIELD_INT(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_INT_ARRAY
+#ifdef DELEGATE_GET_FIELD
+#define DELEGATE_FIELD_INT_ARRAY(id, name)                                     \
+  for (Index i = 0; i < (DELEGATE_GET_FIELD(id, name)).size(); i++) {          \
+    DELEGATE_FIELD_INT(id, name[i]);                                           \
+  }
+#else
+#error please define DELEGATE_FIELD_INT_ARRAY(id, name)
+#endif
+#endif
+
+#ifndef DELEGATE_FIELD_LITERAL
+#error please define DELEGATE_FIELD_LITERAL(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_NAME
+#error please define DELEGATE_FIELD_NAME(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_SCOPE_NAME_DEF
+#error please define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_SCOPE_NAME_USE
+#error please define DELEGATE_FIELD_SCOPE_NAME_USE(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR
+#ifdef DELEGATE_GET_FIELD
+#define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name)                         \
+  for (Index i = 0; i < (DELEGATE_GET_FIELD(id, name)).size(); i++) {          \
+    DELEGATE_FIELD_SCOPE_NAME_USE(id, name[i]);                                \
+  }
+#else
+#error please define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name)
+#endif
+#endif
+
+#ifndef DELEGATE_FIELD_SIGNATURE
+#error please define DELEGATE_FIELD_SIGNATURE(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_TYPE
+#error please define DELEGATE_FIELD_TYPE(id, name)
+#endif
+
+#ifndef DELEGATE_FIELD_ADDRESS
+#error please define DELEGATE_FIELD_ADDRESS(id, name)
+#endif
+
+switch (DELEGATE_ID) {
+  case Expression::Id::InvalidId:
+  case Expression::Id::NumExpressionIds: {
+    WASM_UNREACHABLE("unexpected expression type");
+  }
+  case Expression::Id::BlockId: {
+    DELEGATE_START(Block);
+    DELEGATE_FIELD_CHILD_VECTOR(Block, list);
+    DELEGATE_FIELD_SCOPE_NAME_DEF(Block, name);
+    DELEGATE_END(Block);
+    break;
+  }
+  case Expression::Id::IfId: {
+    DELEGATE_START(If);
+    DELEGATE_FIELD_OPTIONAL_CHILD(If, ifFalse);
+    DELEGATE_FIELD_CHILD(If, ifTrue);
+    DELEGATE_FIELD_CHILD(If, condition);
+    DELEGATE_END(If);
+    break;
+  }
+  case Expression::Id::LoopId: {
+    DELEGATE_START(Loop);
+    DELEGATE_FIELD_CHILD(Loop, body);
+    DELEGATE_FIELD_SCOPE_NAME_DEF(Loop, name);
+    DELEGATE_END(Loop);
+    break;
+  }
+  case Expression::Id::BreakId: {
+    DELEGATE_START(Break);
+    DELEGATE_FIELD_OPTIONAL_CHILD(Break, condition);
+    DELEGATE_FIELD_OPTIONAL_CHILD(Break, value);
+    DELEGATE_FIELD_SCOPE_NAME_USE(Break, name);
+    DELEGATE_END(Break);
+    break;
+  }
+  case Expression::Id::SwitchId: {
+    DELEGATE_START(Switch);
+    DELEGATE_FIELD_CHILD(Switch, condition);
+    DELEGATE_FIELD_OPTIONAL_CHILD(Switch, value);
+    DELEGATE_FIELD_SCOPE_NAME_USE(Switch, default_);
+    DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(Switch, targets);
+    DELEGATE_END(Switch);
+    break;
+  }
+  case Expression::Id::CallId: {
+    DELEGATE_START(Call);
+    DELEGATE_FIELD_CHILD_VECTOR(Call, operands);
+    DELEGATE_FIELD_NAME(Call, target);
+    DELEGATE_FIELD_INT(Call, isReturn);
+    DELEGATE_END(Call);
+    break;
+  }
+  case Expression::Id::CallIndirectId: {
+    DELEGATE_START(CallIndirect);
+    DELEGATE_FIELD_CHILD(CallIndirect, target);
+    DELEGATE_FIELD_CHILD_VECTOR(CallIndirect, operands);
+    DELEGATE_FIELD_SIGNATURE(CallIndirect, sig);
+    DELEGATE_FIELD_INT(CallIndirect, isReturn);
+    DELEGATE_END(CallIndirect);
+    break;
+  }
+  case Expression::Id::LocalGetId: {
+    DELEGATE_START(LocalGet);
+    DELEGATE_FIELD_INT(LocalGet, index);
+    DELEGATE_END(LocalGet);
+    break;
+  }
+  case Expression::Id::LocalSetId: {
+    DELEGATE_START(LocalSet);
+    DELEGATE_FIELD_CHILD(LocalSet, value);
+    DELEGATE_FIELD_INT(LocalSet, index);
+    DELEGATE_END(LocalSet);
+    break;
+  }
+  case Expression::Id::GlobalGetId: {
+    DELEGATE_START(GlobalGet);
+    DELEGATE_FIELD_INT(GlobalGet, name);
+    DELEGATE_END(GlobalGet);
+    break;
+  }
+  case Expression::Id::GlobalSetId: {
+    DELEGATE_START(GlobalSet);
+    DELEGATE_FIELD_CHILD(GlobalSet, value);
+    DELEGATE_FIELD_INT(GlobalSet, name);
+    DELEGATE_END(GlobalSet);
+    break;
+  }
+  case Expression::Id::LoadId: {
+    DELEGATE_START(Load);
+    DELEGATE_FIELD_CHILD(Load, ptr);
+    DELEGATE_FIELD_INT(Load, bytes);
+    DELEGATE_FIELD_INT(Load, signed_);
+    DELEGATE_FIELD_ADDRESS(Load, offset);
+    DELEGATE_FIELD_ADDRESS(Load, align);
+    DELEGATE_FIELD_INT(Load, isAtomic);
+    DELEGATE_END(Load);
+    break;
+  }
+  case Expression::Id::StoreId: {
+    DELEGATE_START(Store);
+    DELEGATE_FIELD_CHILD(Store, value);
+    DELEGATE_FIELD_CHILD(Store, ptr);
+    DELEGATE_FIELD_INT(Store, bytes);
+    DELEGATE_FIELD_ADDRESS(Store, offset);
+    DELEGATE_FIELD_ADDRESS(Store, align);
+    DELEGATE_FIELD_INT(Store, isAtomic);
+    DELEGATE_FIELD_TYPE(Store, valueType);
+    DELEGATE_END(Store);
+    break;
+  }
+  case Expression::Id::AtomicRMWId: {
+    DELEGATE_START(AtomicRMW);
+    DELEGATE_FIELD_CHILD(AtomicRMW, value);
+    DELEGATE_FIELD_CHILD(AtomicRMW, ptr);
+    DELEGATE_FIELD_INT(AtomicRMW, op);
+    DELEGATE_FIELD_INT(AtomicRMW, bytes);
+    DELEGATE_FIELD_ADDRESS(AtomicRMW, offset);
+    DELEGATE_END(AtomicRMW);
+    break;
+  }
+  case Expression::Id::AtomicCmpxchgId: {
+    DELEGATE_START(AtomicCmpxchg);
+    DELEGATE_FIELD_CHILD(AtomicCmpxchg, replacement);
+    DELEGATE_FIELD_CHILD(AtomicCmpxchg, expected);
+    DELEGATE_FIELD_CHILD(AtomicCmpxchg, ptr);
+    DELEGATE_FIELD_INT(AtomicCmpxchg, bytes);
+    DELEGATE_FIELD_ADDRESS(AtomicCmpxchg, offset);
+    DELEGATE_END(AtomicCmpxchgId);
+    break;
+  }
+  case Expression::Id::AtomicWaitId: {
+    DELEGATE_START(AtomicWait);
+    DELEGATE_FIELD_CHILD(AtomicWait, timeout);
+    DELEGATE_FIELD_CHILD(AtomicWait, expected);
+    DELEGATE_FIELD_CHILD(AtomicWait, ptr);
+    DELEGATE_FIELD_ADDRESS(AtomicWait, offset);
+    DELEGATE_FIELD_TYPE(AtomicWait, expectedType);
+    DELEGATE_END(AtomicWait);
+    break;
+  }
+  case Expression::Id::AtomicNotifyId: {
+    DELEGATE_START(AtomicNotify);
+    DELEGATE_FIELD_CHILD(AtomicNotify, notifyCount);
+    DELEGATE_FIELD_CHILD(AtomicNotify, ptr);
+    DELEGATE_FIELD_ADDRESS(AtomicNotify, offset);
+    DELEGATE_END(AtomicNotify);
+    break;
+  }
+  case Expression::Id::AtomicFenceId: {
+    DELEGATE_START(AtomicFence);
+    DELEGATE_FIELD_INT(AtomicFence, order);
+    DELEGATE_END(AtomicFence);
+    break;
+  }
+  case Expression::Id::SIMDExtractId: {
+    DELEGATE_START(SIMDExtract);
+    DELEGATE_FIELD_CHILD(SIMDExtract, vec);
+    DELEGATE_FIELD_INT(SIMDExtract, op);
+    DELEGATE_FIELD_INT(SIMDExtract, index);
+    DELEGATE_END(SIMDExtract);
+    break;
+  }
+  case Expression::Id::SIMDReplaceId: {
+    DELEGATE_START(SIMDReplace);
+    DELEGATE_FIELD_CHILD(SIMDReplace, value);
+    DELEGATE_FIELD_CHILD(SIMDReplace, vec);
+    DELEGATE_FIELD_INT(SIMDReplace, op);
+    DELEGATE_FIELD_INT(SIMDReplace, index);
+    DELEGATE_END(SIMDReplace);
+    break;
+  }
+  case Expression::Id::SIMDShuffleId: {
+    DELEGATE_START(SIMDShuffle);
+    DELEGATE_FIELD_CHILD(SIMDShuffle, right);
+    DELEGATE_FIELD_CHILD(SIMDShuffle, left);
+    DELEGATE_FIELD_INT_ARRAY(SIMDShuffle, mask);
+    DELEGATE_END(SIMDShuffle);
+    break;
+  }
+  case Expression::Id::SIMDTernaryId: {
+    DELEGATE_START(SIMDTernary);
+    DELEGATE_FIELD_CHILD(SIMDTernary, c);
+    DELEGATE_FIELD_CHILD(SIMDTernary, b);
+    DELEGATE_FIELD_CHILD(SIMDTernary, a);
+    DELEGATE_FIELD_INT(SIMDTernary, op);
+    DELEGATE_END(SIMDTernary);
+    break;
+  }
+  case Expression::Id::SIMDShiftId: {
+    DELEGATE_START(SIMDShift);
+    DELEGATE_FIELD_CHILD(SIMDShift, shift);
+    DELEGATE_FIELD_CHILD(SIMDShift, vec);
+    DELEGATE_FIELD_INT(SIMDShift, op);
+    DELEGATE_END(SIMDShift);
+    break;
+  }
+  case Expression::Id::SIMDLoadId: {
+    DELEGATE_START(SIMDLoad);
+    DELEGATE_FIELD_CHILD(SIMDLoad, ptr);
+    DELEGATE_FIELD_INT(SIMDLoad, op);
+    DELEGATE_FIELD_ADDRESS(SIMDLoad, offset);
+    DELEGATE_FIELD_ADDRESS(SIMDLoad, align);
+    DELEGATE_END(SIMDLoad);
+    break;
+  }
+  case Expression::Id::SIMDLoadStoreLaneId: {
+    DELEGATE_START(SIMDLoadStoreLane);
+    DELEGATE_FIELD_CHILD(SIMDLoadStoreLane, vec);
+    DELEGATE_FIELD_CHILD(SIMDLoadStoreLane, ptr);
+    DELEGATE_FIELD_INT(SIMDLoadStoreLane, op);
+    DELEGATE_FIELD_ADDRESS(SIMDLoadStoreLane, offset);
+    DELEGATE_FIELD_ADDRESS(SIMDLoadStoreLane, align);
+    DELEGATE_FIELD_INT(SIMDLoadStoreLane, index);
+    DELEGATE_END(SIMDLoadStoreLane);
+    break;
+  }
+  case Expression::Id::PrefetchId: {
+    DELEGATE_START(Prefetch);
+    DELEGATE_FIELD_CHILD(Prefetch, ptr);
+    DELEGATE_FIELD_INT(Prefetch, op);
+    DELEGATE_FIELD_ADDRESS(Prefetch, offset);
+    DELEGATE_FIELD_ADDRESS(Prefetch, align);
+    DELEGATE_END(Prefetch);
+    break;
+  }
+  case Expression::Id::MemoryInitId: {
+    DELEGATE_START(MemoryInit);
+    DELEGATE_FIELD_CHILD(MemoryInit, size);
+    DELEGATE_FIELD_CHILD(MemoryInit, offset);
+    DELEGATE_FIELD_CHILD(MemoryInit, dest);
+    DELEGATE_FIELD_INT(MemoryInit, segment);
+    DELEGATE_END(MemoryInit);
+    break;
+  }
+  case Expression::Id::DataDropId: {
+    DELEGATE_START(DataDrop);
+    DELEGATE_FIELD_INT(DataDrop, segment);
+    DELEGATE_END(DataDrop);
+    break;
+  }
+  case Expression::Id::MemoryCopyId: {
+    DELEGATE_START(MemoryCopy);
+    DELEGATE_FIELD_CHILD(MemoryCopy, size);
+    DELEGATE_FIELD_CHILD(MemoryCopy, source);
+    DELEGATE_FIELD_CHILD(MemoryCopy, dest);
+    DELEGATE_END(MemoryCopy);
+    break;
+  }
+  case Expression::Id::MemoryFillId: {
+    DELEGATE_START(MemoryFill);
+    DELEGATE_FIELD_CHILD(MemoryFill, size);
+    DELEGATE_FIELD_CHILD(MemoryFill, value);
+    DELEGATE_FIELD_CHILD(MemoryFill, dest);
+    DELEGATE_END(MemoryFill);
+    break;
+  }
+  case Expression::Id::ConstId: {
+    DELEGATE_START(Const);
+    DELEGATE_FIELD_LITERAL(Const, value);
+    DELEGATE_END(Const);
+    break;
+  }
+  case Expression::Id::UnaryId: {
+    DELEGATE_START(Unary);
+    DELEGATE_FIELD_CHILD(Unary, value);
+    DELEGATE_FIELD_INT(Unary, op);
+    DELEGATE_END(Unary);
+    break;
+  }
+  case Expression::Id::BinaryId: {
+    DELEGATE_START(Binary);
+    DELEGATE_FIELD_CHILD(Binary, right);
+    DELEGATE_FIELD_CHILD(Binary, left);
+    DELEGATE_FIELD_INT(Binary, op);
+    DELEGATE_END(Binary);
+    break;
+  }
+  case Expression::Id::SelectId: {
+    DELEGATE_START(Select);
+    DELEGATE_FIELD_CHILD(Select, condition);
+    DELEGATE_FIELD_CHILD(Select, ifFalse);
+    DELEGATE_FIELD_CHILD(Select, ifTrue);
+    DELEGATE_END(Select);
+    break;
+  }
+  case Expression::Id::DropId: {
+    DELEGATE_START(Drop);
+    DELEGATE_FIELD_CHILD(Drop, value);
+    DELEGATE_END(Drop);
+    break;
+  }
+  case Expression::Id::ReturnId: {
+    DELEGATE_START(Return);
+    DELEGATE_FIELD_OPTIONAL_CHILD(Return, value);
+    DELEGATE_END(Return);
+    break;
+  }
+  case Expression::Id::MemorySizeId: {
+    DELEGATE_START(MemorySize);
+    DELEGATE_END(MemorySize);
+    break;
+  }
+  case Expression::Id::MemoryGrowId: {
+    DELEGATE_START(MemoryGrow);
+    DELEGATE_FIELD_CHILD(MemoryGrow, delta);
+    DELEGATE_END(MemoryGrow);
+    break;
+  }
+  case Expression::Id::RefNullId: {
+    DELEGATE_START(RefNull);
+    DELEGATE_FIELD_TYPE(RefNull, type);
+    DELEGATE_END(RefNull);
+    break;
+  }
+  case Expression::Id::RefIsNullId: {
+    DELEGATE_START(RefIsNull);
+    DELEGATE_FIELD_CHILD(RefIsNull, value);
+    DELEGATE_END(RefIsNull);
+    break;
+  }
+  case Expression::Id::RefFuncId: {
+    DELEGATE_START(RefFunc);
+    DELEGATE_FIELD_NAME(RefFunc, func);
+    DELEGATE_END(RefFunc);
+    break;
+  }
+  case Expression::Id::RefEqId: {
+    DELEGATE_START(RefEq);
+    DELEGATE_FIELD_CHILD(RefEq, right);
+    DELEGATE_FIELD_CHILD(RefEq, left);
+    DELEGATE_END(RefEq);
+    break;
+  }
+  case Expression::Id::TryId: {
+    DELEGATE_START(Try);
+    DELEGATE_FIELD_CHILD(Try, catchBody);
+    DELEGATE_FIELD_CHILD(Try, body);
+    DELEGATE_END(Try);
+    break;
+  }
+  case Expression::Id::ThrowId: {
+    DELEGATE_START(Throw);
+    DELEGATE_FIELD_CHILD_VECTOR(Throw, operands);
+    DELEGATE_FIELD_NAME(Throw, event);
+    DELEGATE_END(Throw);
+    break;
+  }
+  case Expression::Id::RethrowId: {
+    DELEGATE_START(Rethrow);
+    DELEGATE_FIELD_CHILD(Rethrow, exnref);
+    DELEGATE_END(Rethrow);
+    break;
+  }
+  case Expression::Id::BrOnExnId: {
+    DELEGATE_START(BrOnExn);
+    DELEGATE_FIELD_CHILD(BrOnExn, exnref);
+    DELEGATE_FIELD_SCOPE_NAME_USE(BrOnExn, name);
+    DELEGATE_FIELD_NAME(BrOnExn, event);
+    DELEGATE_FIELD_TYPE(BrOnExn, sent);
+    DELEGATE_END(BrOnExn);
+    break;
+  }
+  case Expression::Id::NopId: {
+    DELEGATE_START(Nop);
+    DELEGATE_END(Nop);
+    break;
+  }
+  case Expression::Id::UnreachableId: {
+    DELEGATE_START(Unreachable);
+    DELEGATE_END(Unreachable);
+    break;
+  }
+  case Expression::Id::PopId: {
+    DELEGATE_START(Pop);
+    DELEGATE_END(Pop);
+    break;
+  }
+  case Expression::Id::TupleMakeId: {
+    DELEGATE_START(TupleMake);
+    DELEGATE_FIELD_CHILD_VECTOR(Tuple, operands);
+    DELEGATE_END(TupleMake);
+    break;
+  }
+  case Expression::Id::TupleExtractId: {
+    DELEGATE_START(TupleExtract);
+    DELEGATE_FIELD_CHILD(TupleExtract, tuple);
+    DELEGATE_FIELD_INT(TupleExtract, index);
+    DELEGATE_END(TupleExtract);
+    break;
+  }
+  case Expression::Id::I31NewId: {
+    DELEGATE_START(I31New);
+    DELEGATE_FIELD_CHILD(I31New, value);
+    DELEGATE_END(I31New);
+    break;
+  }
+  case Expression::Id::I31GetId: {
+    DELEGATE_START(I31Get);
+    DELEGATE_FIELD_CHILD(I31Get, i31);
+    DELEGATE_FIELD_INT(I31Get, signed_);
+    DELEGATE_END(I31Get);
+    break;
+  }
+  case Expression::Id::CallRefId: {
+    DELEGATE_START(CallRef);
+    DELEGATE_FIELD_CHILD(CallRef, target);
+    DELEGATE_FIELD_CHILD_VECTOR(CallRef, operands);
+    DELEGATE_FIELD_INT(CallRef, isReturn);
+    DELEGATE_END(CallRef);
+    break;
+  }
+  case Expression::Id::RefTestId: {
+    DELEGATE_START(RefTest);
+    DELEGATE_FIELD_CHILD(RefTest, ref);
+    DELEGATE_FIELD_CHILD(RefTest, rtt);
+    DELEGATE_END(RefTest);
+    break;
+  }
+  case Expression::Id::RefCastId: {
+    DELEGATE_START(RefCast);
+    DELEGATE_FIELD_CHILD(RefCast, ref);
+    DELEGATE_FIELD_CHILD(RefCast, rtt);
+    DELEGATE_END(RefCast);
+    break;
+  }
+  case Expression::Id::BrOnCastId: {
+    DELEGATE_START(BrOnCast);
+    DELEGATE_FIELD_SCOPE_NAME_USE(BrOnCast, name);
+    DELEGATE_FIELD_TYPE(BrOnCast, castType);
+    DELEGATE_FIELD_CHILD(BrOnCast, ref);
+    DELEGATE_FIELD_CHILD(BrOnCast, rtt);
+    DELEGATE_END(BrOnCast);
+    break;
+  }
+  case Expression::Id::RttCanonId: {
+    DELEGATE_START(RttCanon);
+    DELEGATE_END(RttCanon);
+    break;
+  }
+  case Expression::Id::RttSubId: {
+    DELEGATE_START(RttSub);
+    DELEGATE_FIELD_CHILD(RttSub, parent);
+    DELEGATE_END(RttSub);
+    break;
+  }
+  case Expression::Id::StructNewId: {
+    DELEGATE_START(StructNew);
+    DELEGATE_FIELD_CHILD(StructNew, rtt);
+    DELEGATE_FIELD_CHILD_VECTOR(StructNew, operands);
+    DELEGATE_END(StructNew);
+    break;
+  }
+  case Expression::Id::StructGetId: {
+    DELEGATE_START(StructGet);
+    DELEGATE_FIELD_INT(StructGet, index);
+    DELEGATE_FIELD_CHILD(StructGet, ref);
+    DELEGATE_FIELD_INT(StructGet, signed_);
+    DELEGATE_END(StructGet);
+    break;
+  }
+  case Expression::Id::StructSetId: {
+    DELEGATE_START(StructSet);
+    DELEGATE_FIELD_INT(StructSet, index);
+    DELEGATE_FIELD_CHILD(StructSet, ref);
+    DELEGATE_FIELD_CHILD(StructSet, value);
+    DELEGATE_END(StructSet);
+    break;
+  }
+  case Expression::Id::ArrayNewId: {
+    DELEGATE_START(ArrayNew);
+    DELEGATE_FIELD_CHILD(ArrayNew, rtt);
+    DELEGATE_FIELD_CHILD(ArrayNew, size);
+    DELEGATE_FIELD_OPTIONAL_CHILD(ArrayNew, init);
+    DELEGATE_END(ArrayNew);
+    break;
+  }
+  case Expression::Id::ArrayGetId: {
+    DELEGATE_START(ArrayGet);
+    DELEGATE_FIELD_CHILD(ArrayGet, ref);
+    DELEGATE_FIELD_CHILD(ArrayGet, index);
+    DELEGATE_FIELD_INT(ArrayGet, signed_);
+    DELEGATE_END(ArrayGet);
+    break;
+  }
+  case Expression::Id::ArraySetId: {
+    DELEGATE_START(ArraySet);
+    DELEGATE_FIELD_CHILD(ArrayGet, ref);
+    DELEGATE_FIELD_CHILD(ArrayGet, index);
+    DELEGATE_FIELD_CHILD(ArrayGet, value);
+    DELEGATE_END(ArraySet);
+    break;
+  }
+  case Expression::Id::ArrayLenId: {
+    DELEGATE_START(ArrayLen);
+    DELEGATE_FIELD_CHILD(ArrayLen, ref);
+    DELEGATE_END(ArrayLen);
+    break;
+  }
+}
+
+#undef DELEGATE_ID
+#undef DELEGATE_START
+#undef DELEGATE_END
+#undef DELEGATE_FIELD_CHILD
+#undef DELEGATE_FIELD_OPTIONAL_CHILD
+#undef DELEGATE_FIELD_CHILD_VECTOR
+#undef DELEGATE_FIELD_INT
+#undef DELEGATE_FIELD_INT_ARRAY
+#undef DELEGATE_FIELD_LITERAL
+#undef DELEGATE_FIELD_NAME
+#undef DELEGATE_FIELD_SCOPE_NAME_DEF
+#undef DELEGATE_FIELD_SCOPE_NAME_USE
+#undef DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR
+#undef DELEGATE_FIELD_SIGNATURE
+#undef DELEGATE_FIELD_TYPE
+#undef DELEGATE_FIELD_ADDRESS
+#undef DELEGATE_GET_FIELD
diff --git a/binaryen/src/wasm-delegations.h b/binaryen/src/wasm-delegations.h
new file mode 100644
--- /dev/null
+++ b/binaryen/src/wasm-delegations.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+DELEGATE(Nop);
+DELEGATE(Block);
+DELEGATE(If);
+DELEGATE(Loop);
+DELEGATE(Break);
+DELEGATE(Switch);
+DELEGATE(Call);
+DELEGATE(CallIndirect);
+DELEGATE(LocalGet);
+DELEGATE(LocalSet);
+DELEGATE(GlobalGet);
+DELEGATE(GlobalSet);
+DELEGATE(Load);
+DELEGATE(Store);
+DELEGATE(AtomicRMW);
+DELEGATE(AtomicCmpxchg);
+DELEGATE(AtomicWait);
+DELEGATE(AtomicNotify);
+DELEGATE(AtomicFence);
+DELEGATE(SIMDExtract);
+DELEGATE(SIMDReplace);
+DELEGATE(SIMDShuffle);
+DELEGATE(SIMDTernary);
+DELEGATE(SIMDShift);
+DELEGATE(SIMDLoad);
+DELEGATE(SIMDLoadStoreLane);
+DELEGATE(Prefetch);
+DELEGATE(MemoryInit);
+DELEGATE(DataDrop);
+DELEGATE(MemoryCopy);
+DELEGATE(MemoryFill);
+DELEGATE(Const);
+DELEGATE(Unary);
+DELEGATE(Binary);
+DELEGATE(Select);
+DELEGATE(Drop);
+DELEGATE(Return);
+DELEGATE(MemorySize);
+DELEGATE(MemoryGrow);
+DELEGATE(Unreachable);
+DELEGATE(Pop);
+DELEGATE(RefNull);
+DELEGATE(RefIsNull);
+DELEGATE(RefFunc);
+DELEGATE(RefEq);
+DELEGATE(Try);
+DELEGATE(Throw);
+DELEGATE(Rethrow);
+DELEGATE(BrOnExn);
+DELEGATE(TupleMake);
+DELEGATE(TupleExtract);
+DELEGATE(I31New);
+DELEGATE(I31Get);
+DELEGATE(CallRef);
+DELEGATE(RefTest);
+DELEGATE(RefCast);
+DELEGATE(BrOnCast);
+DELEGATE(RttCanon);
+DELEGATE(RttSub);
+DELEGATE(StructNew);
+DELEGATE(StructGet);
+DELEGATE(StructSet);
+DELEGATE(ArrayNew);
+DELEGATE(ArrayGet);
+DELEGATE(ArraySet);
+DELEGATE(ArrayLen);
+
+#undef DELEGATE
diff --git a/binaryen/src/wasm-emscripten.h b/binaryen/src/wasm-emscripten.h
--- a/binaryen/src/wasm-emscripten.h
+++ b/binaryen/src/wasm-emscripten.h
@@ -33,16 +33,7 @@
     : wasm(wasm), builder(wasm), stackPointerOffset(stackPointerOffset),
       useStackPointerGlobal(stackPointerOffset == 0) {}
 
-  Function* generateAssignGOTEntriesFunction();
-  void generatePostInstantiateFunction();
-
-  // Remove the import of a mutable __stack_pointer and instead initialize the
-  // stack pointer from an immutable import.
-  void internalizeStackPointerGlobal();
-
-  std::string
-  generateEmscriptenMetadata(Address staticBump,
-                             std::vector<Name> const& initializerFunctions);
+  std::string generateEmscriptenMetadata(Name initializer);
 
   void fixInvokeFunctionNames();
 
diff --git a/binaryen/src/wasm-features.h b/binaryen/src/wasm-features.h
--- a/binaryen/src/wasm-features.h
+++ b/binaryen/src/wasm-features.h
@@ -38,7 +38,8 @@
     Multivalue = 1 << 9,
     GC = 1 << 10,
     Memory64 = 1 << 11,
-    All = (1 << 12) - 1
+    TypedFunctionReferences = 1 << 12,
+    All = (1 << 13) - 1
   };
 
   static std::string toString(Feature f) {
@@ -67,6 +68,8 @@
         return "gc";
       case Memory64:
         return "memory64";
+      case TypedFunctionReferences:
+        return "typed-function-references";
       default:
         WASM_UNREACHABLE("unexpected feature");
     }
@@ -92,6 +95,9 @@
   bool hasMultivalue() const { return (features & Multivalue) != 0; }
   bool hasGC() const { return (features & GC) != 0; }
   bool hasMemory64() const { return (features & Memory64) != 0; }
+  bool hasTypedFunctionReferences() const {
+    return (features & TypedFunctionReferences) != 0;
+  }
   bool hasAll() const { return (features & All) != 0; }
 
   void makeMVP() { features = MVP; }
@@ -110,6 +116,9 @@
   void setMultivalue(bool v = true) { set(Multivalue, v); }
   void setGC(bool v = true) { set(GC, v); }
   void setMemory64(bool v = true) { set(Memory64, v); }
+  void setTypedFunctionReferences(bool v = true) {
+    set(TypedFunctionReferences, v);
+  }
   void setAll(bool v = true) { features = v ? All : MVP; }
 
   void enable(const FeatureSet& other) { features |= other.features; }
diff --git a/binaryen/src/wasm-interpreter.h b/binaryen/src/wasm-interpreter.h
--- a/binaryen/src/wasm-interpreter.h
+++ b/binaryen/src/wasm-interpreter.h
@@ -60,6 +60,7 @@
   Flow(Literals& values) : values(values) {}
   Flow(Literals&& values) : values(std::move(values)) {}
   Flow(Name breakTo) : values(), breakTo(breakTo) {}
+  Flow(Name breakTo, Literal value) : values{value}, breakTo(breakTo) {}
 
   Literals values;
   Name breakTo; // if non-null, a break is going on
@@ -463,6 +464,8 @@
         return value.allTrueI8x16();
       case BitmaskVecI8x16:
         return value.bitmaskI8x16();
+      case PopcntVecI8x16:
+        return value.popcntI8x16();
       case AbsVecI16x8:
         return value.absI16x8();
       case NegVecI16x8:
@@ -485,10 +488,8 @@
         return value.bitmaskI32x4();
       case NegVecI64x2:
         return value.negI64x2();
-      case AnyTrueVecI64x2:
-        return value.anyTrueI64x2();
-      case AllTrueVecI64x2:
-        return value.allTrueI64x2();
+      case BitmaskVecI64x2:
+        WASM_UNREACHABLE("unimp");
       case AbsVecF32x4:
         return value.absF32x4();
       case NegVecF32x4:
@@ -517,6 +518,14 @@
         return value.truncF64x2();
       case NearestVecF64x2:
         return value.nearestF64x2();
+      case ExtAddPairwiseSVecI8x16ToI16x8:
+        WASM_UNREACHABLE("unimp");
+      case ExtAddPairwiseUVecI8x16ToI16x8:
+        WASM_UNREACHABLE("unimp");
+      case ExtAddPairwiseSVecI16x8ToI32x4:
+        WASM_UNREACHABLE("unimp");
+      case ExtAddPairwiseUVecI16x8ToI32x4:
+        WASM_UNREACHABLE("unimp");
       case TruncSatSVecF32x4ToVecI32x4:
         return value.truncSatToSI32x4();
       case TruncSatUVecF32x4ToVecI32x4:
@@ -549,6 +558,11 @@
         return value.widenLowUToVecI32x4();
       case WidenHighUVecI16x8ToVecI32x4:
         return value.widenHighUToVecI32x4();
+      case WidenLowSVecI32x4ToVecI64x2:
+      case WidenHighSVecI32x4ToVecI64x2:
+      case WidenLowUVecI32x4ToVecI64x2:
+      case WidenHighUVecI32x4ToVecI64x2:
+        WASM_UNREACHABLE("unimp");
       case InvalidUnary:
         WASM_UNREACHABLE("invalid unary op");
     }
@@ -794,6 +808,8 @@
         return left.geSI32x4(right);
       case GeUVecI32x4:
         return left.geUI32x4(right);
+      case EqVecI64x2:
+        return left.eqI64x2(right);
       case EqVecF32x4:
         return left.eqF32x4(right);
       case NeVecF32x4:
@@ -876,6 +892,16 @@
         return left.maxUI16x8(right);
       case AvgrUVecI16x8:
         return left.avgrUI16x8(right);
+      case Q15MulrSatSVecI16x8:
+        return left.q15MulrSatSI16x8(right);
+      case ExtMulLowSVecI16x8:
+        return left.extMulLowSI16x8(right);
+      case ExtMulHighSVecI16x8:
+        return left.extMulHighSI16x8(right);
+      case ExtMulLowUVecI16x8:
+        return left.extMulLowUI16x8(right);
+      case ExtMulHighUVecI16x8:
+        return left.extMulHighUI16x8(right);
       case AddVecI32x4:
         return left.addI32x4(right);
       case SubVecI32x4:
@@ -892,12 +918,28 @@
         return left.maxUI32x4(right);
       case DotSVecI16x8ToVecI32x4:
         return left.dotSI16x8toI32x4(right);
+      case ExtMulLowSVecI32x4:
+        return left.extMulLowSI32x4(right);
+      case ExtMulHighSVecI32x4:
+        return left.extMulHighSI32x4(right);
+      case ExtMulLowUVecI32x4:
+        return left.extMulLowUI32x4(right);
+      case ExtMulHighUVecI32x4:
+        return left.extMulHighUI32x4(right);
       case AddVecI64x2:
         return left.addI64x2(right);
       case SubVecI64x2:
         return left.subI64x2(right);
       case MulVecI64x2:
         return left.mulI64x2(right);
+      case ExtMulLowSVecI64x2:
+        return left.extMulLowSI64x2(right);
+      case ExtMulHighSVecI64x2:
+        return left.extMulHighSI64x2(right);
+      case ExtMulLowUVecI64x2:
+        return left.extMulLowUI64x2(right);
+      case ExtMulHighUVecI64x2:
+        return left.extMulHighUI64x2(right);
 
       case AddVecF32x4:
         return left.addF32x4(right);
@@ -1039,7 +1081,7 @@
       case Bitselect:
         return c.bitselectV128(a, b);
       default:
-        // TODO: implement qfma/qfms
+        // TODO: implement qfma/qfms and signselect
         WASM_UNREACHABLE("not implemented");
     }
   }
@@ -1125,6 +1167,14 @@
     NOTE_ENTER("Nop");
     return Flow();
   }
+  Flow visitPrefetch(Prefetch* curr) {
+    NOTE_ENTER("Prefetch");
+    Flow flow = visit(curr->ptr);
+    if (flow.breaking()) {
+      return flow;
+    }
+    return Flow();
+  }
   Flow visitUnreachable(Unreachable* curr) {
     NOTE_ENTER("Unreachable");
     trap("unreachable");
@@ -1240,7 +1290,11 @@
   Flow visitSIMDLoadSplat(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
   Flow visitSIMDLoadExtend(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
   Flow visitSIMDLoadZero(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+    WASM_UNREACHABLE("unimp");
+  }
   Flow visitPop(Pop* curr) { WASM_UNREACHABLE("unimp"); }
+  Flow visitCallRef(CallRef* curr) { WASM_UNREACHABLE("unimp"); }
   Flow visitRefNull(RefNull* curr) {
     NOTE_ENTER("RefNull");
     return Literal::makeNull(curr->type);
@@ -1258,7 +1312,7 @@
   Flow visitRefFunc(RefFunc* curr) {
     NOTE_ENTER("RefFunc");
     NOTE_NAME(curr->func);
-    return Literal::makeFunc(curr->func);
+    return Literal::makeFunc(curr->func, curr->type);
   }
   Flow visitRefEq(RefEq* curr) {
     NOTE_ENTER("RefEq");
@@ -1344,58 +1398,287 @@
     NOTE_EVAL1(value);
     return Literal(value.geti31(curr->signed_));
   }
+
+  // Helper for ref.test, ref.cast, and br_on_cast, which share almost all their
+  // logic except for what they return.
+  struct Cast {
+    enum Outcome {
+      // We took a break before doing anything.
+      Break,
+      // The input was null.
+      Null,
+      // The cast succeeded.
+      Success,
+      // The cast failed.
+      Failure
+    } outcome;
+
+    Flow breaking;
+    Literal originalRef;
+    Literal castRef;
+  };
+
+  template<typename T> Cast doCast(T* curr) {
+    Cast cast;
+    Flow ref = this->visit(curr->ref);
+    if (ref.breaking()) {
+      cast.outcome = cast.Break;
+      cast.breaking = ref;
+      return cast;
+    }
+    Flow rtt = this->visit(curr->rtt);
+    if (rtt.breaking()) {
+      cast.outcome = cast.Break;
+      cast.breaking = rtt;
+      return cast;
+    }
+    cast.originalRef = ref.getSingleValue();
+    auto gcData = cast.originalRef.getGCData();
+    if (!gcData) {
+      cast.outcome = cast.Null;
+      return cast;
+    }
+    auto refRtt = gcData->rtt;
+    auto intendedRtt = rtt.getSingleValue();
+    if (!refRtt.isSubRtt(intendedRtt)) {
+      cast.outcome = cast.Failure;
+    } else {
+      cast.outcome = cast.Success;
+      cast.castRef =
+        Literal(gcData, Type(intendedRtt.type.getHeapType(), Nullable));
+    }
+    return cast;
+  }
+
   Flow visitRefTest(RefTest* curr) {
     NOTE_ENTER("RefTest");
-    WASM_UNREACHABLE("TODO (gc): ref.test");
+    auto cast = doCast(curr);
+    if (cast.outcome == cast.Break) {
+      return cast.breaking;
+    }
+    return Literal(int32_t(cast.outcome == cast.Success));
   }
   Flow visitRefCast(RefCast* curr) {
     NOTE_ENTER("RefCast");
-    WASM_UNREACHABLE("TODO (gc): ref.cast");
+    auto cast = doCast(curr);
+    if (cast.outcome == cast.Break) {
+      return cast.breaking;
+    }
+    if (cast.outcome == cast.Null) {
+      return Literal::makeNull(curr->type);
+    }
+    if (cast.outcome == cast.Failure) {
+      trap("cast error");
+    }
+    assert(cast.outcome == cast.Success);
+    return cast.castRef;
   }
   Flow visitBrOnCast(BrOnCast* curr) {
     NOTE_ENTER("BrOnCast");
-    WASM_UNREACHABLE("TODO (gc): br_on_cast");
-  }
-  Flow visitRttCanon(RttCanon* curr) {
-    NOTE_ENTER("RttCanon");
-    WASM_UNREACHABLE("TODO (gc): rtt.canon");
+    auto cast = doCast(curr);
+    if (cast.outcome == cast.Break) {
+      return cast.breaking;
+    }
+    if (cast.outcome == cast.Null || cast.outcome == cast.Failure) {
+      return cast.originalRef;
+    }
+    assert(cast.outcome == cast.Success);
+    return Flow(curr->name, cast.castRef);
   }
+  Flow visitRttCanon(RttCanon* curr) { return Literal(curr->type); }
   Flow visitRttSub(RttSub* curr) {
-    NOTE_ENTER("RttSub");
-    WASM_UNREACHABLE("TODO (gc): rtt.sub");
+    Flow parent = this->visit(curr->parent);
+    if (parent.breaking()) {
+      return parent;
+    }
+    auto parentValue = parent.getSingleValue();
+    auto newSupers = std::make_unique<RttSupers>(parentValue.getRttSupers());
+    newSupers->push_back(parentValue.type);
+    return Literal(std::move(newSupers), curr->type);
   }
   Flow visitStructNew(StructNew* curr) {
     NOTE_ENTER("StructNew");
-    WASM_UNREACHABLE("TODO (gc): struct.new");
+    auto rtt = this->visit(curr->rtt);
+    if (rtt.breaking()) {
+      return rtt;
+    }
+    const auto& fields = curr->rtt->type.getHeapType().getStruct().fields;
+    Literals data(fields.size());
+    for (Index i = 0; i < fields.size(); i++) {
+      if (curr->isWithDefault()) {
+        data[i] = Literal::makeZero(fields[i].type);
+      } else {
+        auto value = this->visit(curr->operands[i]);
+        if (value.breaking()) {
+          return value;
+        }
+        data[i] = value.getSingleValue();
+      }
+    }
+    return Flow(Literal(std::make_shared<GCData>(rtt.getSingleValue(), data),
+                        curr->type));
   }
   Flow visitStructGet(StructGet* curr) {
     NOTE_ENTER("StructGet");
-    WASM_UNREACHABLE("TODO (gc): struct.get");
+    Flow ref = this->visit(curr->ref);
+    if (ref.breaking()) {
+      return ref;
+    }
+    auto data = ref.getSingleValue().getGCData();
+    if (!data) {
+      trap("null ref");
+    }
+    auto field = curr->ref->type.getHeapType().getStruct().fields[curr->index];
+    return extendForPacking(data->values[curr->index], field, curr->signed_);
   }
   Flow visitStructSet(StructSet* curr) {
     NOTE_ENTER("StructSet");
-    WASM_UNREACHABLE("TODO (gc): struct.set");
+    Flow ref = this->visit(curr->ref);
+    if (ref.breaking()) {
+      return ref;
+    }
+    Flow value = this->visit(curr->value);
+    if (value.breaking()) {
+      return value;
+    }
+    auto data = ref.getSingleValue().getGCData();
+    if (!data) {
+      trap("null ref");
+    }
+    auto field = curr->ref->type.getHeapType().getStruct().fields[curr->index];
+    data->values[curr->index] =
+      truncateForPacking(value.getSingleValue(), field);
+    return Flow();
   }
   Flow visitArrayNew(ArrayNew* curr) {
     NOTE_ENTER("ArrayNew");
-    WASM_UNREACHABLE("TODO (gc): array.new");
+    auto rtt = this->visit(curr->rtt);
+    if (rtt.breaking()) {
+      return rtt;
+    }
+    auto size = this->visit(curr->size);
+    if (size.breaking()) {
+      return size;
+    }
+    const auto& element = curr->rtt->type.getHeapType().getArray().element;
+    Index num = size.getSingleValue().geti32();
+    Literals data(num);
+    if (curr->isWithDefault()) {
+      for (Index i = 0; i < num; i++) {
+        data[i] = Literal::makeZero(element.type);
+      }
+    } else {
+      auto init = this->visit(curr->init);
+      if (init.breaking()) {
+        return init;
+      }
+      auto value = init.getSingleValue();
+      for (Index i = 0; i < num; i++) {
+        data[i] = value;
+      }
+    }
+    return Flow(Literal(std::make_shared<GCData>(rtt.getSingleValue(), data),
+                        curr->type));
   }
   Flow visitArrayGet(ArrayGet* curr) {
     NOTE_ENTER("ArrayGet");
-    WASM_UNREACHABLE("TODO (gc): array.get");
+    Flow ref = this->visit(curr->ref);
+    if (ref.breaking()) {
+      return ref;
+    }
+    Flow index = this->visit(curr->index);
+    if (index.breaking()) {
+      return index;
+    }
+    auto data = ref.getSingleValue().getGCData();
+    if (!data) {
+      trap("null ref");
+    }
+    Index i = index.getSingleValue().geti32();
+    if (i >= data->values.size()) {
+      trap("array oob");
+    }
+    auto field = curr->ref->type.getHeapType().getArray().element;
+    return extendForPacking(data->values[i], field, curr->signed_);
   }
   Flow visitArraySet(ArraySet* curr) {
     NOTE_ENTER("ArraySet");
-    WASM_UNREACHABLE("TODO (gc): array.set");
+    Flow ref = this->visit(curr->ref);
+    if (ref.breaking()) {
+      return ref;
+    }
+    Flow index = this->visit(curr->index);
+    if (index.breaking()) {
+      return index;
+    }
+    Flow value = this->visit(curr->value);
+    if (value.breaking()) {
+      return value;
+    }
+    auto data = ref.getSingleValue().getGCData();
+    if (!data) {
+      trap("null ref");
+    }
+    Index i = index.getSingleValue().geti32();
+    if (i >= data->values.size()) {
+      trap("array oob");
+    }
+    auto field = curr->ref->type.getHeapType().getArray().element;
+    data->values[i] = truncateForPacking(value.getSingleValue(), field);
+    return Flow();
   }
   Flow visitArrayLen(ArrayLen* curr) {
     NOTE_ENTER("ArrayLen");
-    WASM_UNREACHABLE("TODO (gc): array.len");
+    Flow ref = this->visit(curr->ref);
+    if (ref.breaking()) {
+      return ref;
+    }
+    auto data = ref.getSingleValue().getGCData();
+    if (!data) {
+      trap("null ref");
+    }
+    return Literal(int32_t(data->values.size()));
   }
 
   virtual void trap(const char* why) { WASM_UNREACHABLE("unimp"); }
 
   virtual void throwException(Literal exn) { WASM_UNREACHABLE("unimp"); }
+
+private:
+  // Truncate the value if we need to. The storage is just a list of Literals,
+  // so we can't just write the value like we would to a C struct field and
+  // expect it to truncate for us. Instead, we truncate so the stored value is
+  // proper for the type.
+  Literal truncateForPacking(Literal value, const Field& field) {
+    if (field.type == Type::i32) {
+      int32_t c = value.geti32();
+      if (field.packedType == Field::i8) {
+        value = Literal(c & 0xff);
+      } else if (field.packedType == Field::i16) {
+        value = Literal(c & 0xffff);
+      }
+    }
+    return value;
+  }
+
+  Literal extendForPacking(Literal value, const Field& field, bool signed_) {
+    if (field.type == Type::i32) {
+      int32_t c = value.geti32();
+      if (field.packedType == Field::i8) {
+        // The stored value should already be truncated.
+        assert(c == (c & 0xff));
+        if (signed_) {
+          value = Literal((c << 24) >> 24);
+        }
+      } else if (field.packedType == Field::i16) {
+        assert(c == (c & 0xffff));
+        if (signed_) {
+          value = Literal((c << 16) >> 16);
+        }
+      }
+    }
+    return value;
+  }
 };
 
 // Execute a suspected constant expression (precompute and C-API).
@@ -1562,11 +1845,14 @@
     }
     return Flow(NONCONSTANT_FLOW);
   }
-
   Flow visitCallIndirect(CallIndirect* curr) {
     NOTE_ENTER("CallIndirect");
     return Flow(NONCONSTANT_FLOW);
   }
+  Flow visitCallRef(CallRef* curr) {
+    NOTE_ENTER("CallRef");
+    return Flow(NONCONSTANT_FLOW);
+  }
   Flow visitLoad(Load* curr) {
     NOTE_ENTER("Load");
     return Flow(NONCONSTANT_FLOW);
@@ -1627,6 +1913,10 @@
     NOTE_ENTER("SIMDLoadExtend");
     return Flow(NONCONSTANT_FLOW);
   }
+  Flow visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+    NOTE_ENTER("SIMDLoadStoreLane");
+    return Flow(NONCONSTANT_FLOW);
+  }
   Flow visitPop(Pop* curr) {
     NOTE_ENTER("Pop");
     return Flow(NONCONSTANT_FLOW);
@@ -2060,6 +2350,37 @@
       }
       return ret;
     }
+    Flow visitCallRef(CallRef* curr) {
+      NOTE_ENTER("CallRef");
+      LiteralList arguments;
+      Flow flow = this->generateArguments(curr->operands, arguments);
+      if (flow.breaking()) {
+        return flow;
+      }
+      Flow target = this->visit(curr->target);
+      if (target.breaking()) {
+        return target;
+      }
+      if (target.getSingleValue().isNull()) {
+        trap("null target in call_ref");
+      }
+      Name funcName = target.getSingleValue().getFunc();
+      auto* func = instance.wasm.getFunction(funcName);
+      Flow ret;
+      if (func->imported()) {
+        ret.values = instance.externalInterface->callImport(func, arguments);
+      } else {
+        ret.values = instance.callFunctionInternal(funcName, arguments);
+      }
+#ifdef WASM_INTERPRETER_DEBUG
+      std::cout << "(returned to " << scope.function->name << ")\n";
+#endif
+      // TODO: make this a proper tail call (return first)
+      if (curr->isReturn) {
+        ret.breakTo = RETURN_FLOW;
+      }
+      return ret;
+    }
 
     Flow visitLocalGet(LocalGet* curr) {
       NOTE_ENTER("LocalGet");
@@ -2158,22 +2479,22 @@
       NOTE_EVAL1(loaded);
       auto computed = value.getSingleValue();
       switch (curr->op) {
-        case Add:
+        case RMWAdd:
           computed = loaded.add(computed);
           break;
-        case Sub:
+        case RMWSub:
           computed = loaded.sub(computed);
           break;
-        case And:
+        case RMWAnd:
           computed = loaded.and_(computed);
           break;
-        case Or:
+        case RMWOr:
           computed = loaded.or_(computed);
           break;
-        case Xor:
+        case RMWXor:
           computed = loaded.xor_(computed);
           break;
-        case Xchg:
+        case RMWXchg:
           break;
       }
       instance.doAtomicStore(addr, curr->bytes, computed);
@@ -2369,7 +2690,7 @@
       }
       NOTE_EVAL1(flow);
       Address src = instance.getFinalAddress(
-        curr, flow.getSingleValue(), curr->op == Load32Zero ? 32 : 64);
+        curr, flow.getSingleValue(), curr->getMemBytes());
       auto zero =
         Literal::makeZero(curr->op == Load32Zero ? Type::i32 : Type::i64);
       if (curr->op == Load32Zero) {
@@ -2379,6 +2700,76 @@
         auto val = Literal(instance.externalInterface->load64u(src));
         return Literal(std::array<Literal, 2>{{val, zero}});
       }
+    }
+    Flow visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+      NOTE_ENTER("SIMDLoadStoreLane");
+      Flow flow = this->visit(curr->ptr);
+      if (flow.breaking()) {
+        return flow;
+      }
+      NOTE_EVAL1(flow);
+      Address addr = instance.getFinalAddress(
+        curr, flow.getSingleValue(), curr->getMemBytes());
+      flow = this->visit(curr->vec);
+      if (flow.breaking()) {
+        return flow;
+      }
+      Literal vec = flow.getSingleValue();
+      switch (curr->op) {
+        case LoadLaneVec8x16:
+        case StoreLaneVec8x16: {
+          std::array<Literal, 16> lanes = vec.getLanesUI8x16();
+          if (curr->isLoad()) {
+            lanes[curr->index] =
+              Literal(instance.externalInterface->load8u(addr));
+            return Literal(lanes);
+          } else {
+            instance.externalInterface->store8(addr,
+                                               lanes[curr->index].geti32());
+            return {};
+          }
+        }
+        case LoadLaneVec16x8:
+        case StoreLaneVec16x8: {
+          std::array<Literal, 8> lanes = vec.getLanesUI16x8();
+          if (curr->isLoad()) {
+            lanes[curr->index] =
+              Literal(instance.externalInterface->load16u(addr));
+            return Literal(lanes);
+          } else {
+            instance.externalInterface->store16(addr,
+                                                lanes[curr->index].geti32());
+            return {};
+          }
+        }
+        case LoadLaneVec32x4:
+        case StoreLaneVec32x4: {
+          std::array<Literal, 4> lanes = vec.getLanesI32x4();
+          if (curr->isLoad()) {
+            lanes[curr->index] =
+              Literal(instance.externalInterface->load32u(addr));
+            return Literal(lanes);
+          } else {
+            instance.externalInterface->store32(addr,
+                                                lanes[curr->index].geti32());
+            return {};
+          }
+        }
+        case StoreLaneVec64x2:
+        case LoadLaneVec64x2: {
+          std::array<Literal, 2> lanes = vec.getLanesI64x2();
+          if (curr->isLoad()) {
+            lanes[curr->index] =
+              Literal(instance.externalInterface->load64u(addr));
+            return Literal(lanes);
+          } else {
+            instance.externalInterface->store64(addr,
+                                                lanes[curr->index].geti64());
+            return {};
+          }
+        }
+      }
+      WASM_UNREACHABLE("unexpected op");
     }
     Flow visitMemorySize(MemorySize* curr) {
       NOTE_ENTER("MemorySize");
diff --git a/binaryen/src/wasm-module-building.h b/binaryen/src/wasm-module-building.h
--- a/binaryen/src/wasm-module-building.h
+++ b/binaryen/src/wasm-module-building.h
@@ -122,15 +122,6 @@
       return;
     }
 
-    // Before parallelism, create all passes on the main thread here, to ensure
-    // prepareToRun() is called for each pass before we start to optimize
-    // functions.
-    {
-      PassRunner passRunner(wasm, passOptions);
-      addPrePasses(passRunner);
-      passRunner.addDefaultFunctionOptimizationPasses();
-    }
-
     // prepare work list
     endMarker = new Function();
     list = new std::atomic<Function*>[numFunctions];
diff --git a/binaryen/src/wasm-printing.h b/binaryen/src/wasm-printing.h
deleted file mode 100644
--- a/binaryen/src/wasm-printing.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef wasm_wasm_printing_h
-#define wasm_wasm_printing_h
-
-#include <ostream>
-
-#include "pass.h"
-#include "wasm.h"
-
-namespace wasm {
-
-struct WasmPrinter {
-  static std::ostream& printModule(Module* module, std::ostream& o);
-
-  static std::ostream& printModule(Module* module);
-
-  static std::ostream& printExpression(Expression* expression,
-                                       std::ostream& o,
-                                       bool minify = false,
-                                       bool full = false);
-
-  static std::ostream&
-  printStackInst(StackInst* inst, std::ostream& o, Function* func = nullptr);
-
-  static std::ostream&
-  printStackIR(StackIR* ir, std::ostream& o, Function* func = nullptr);
-};
-
-} // namespace wasm
-
-namespace std {
-
-inline std::ostream& operator<<(std::ostream& o, wasm::Module& module) {
-  return wasm::WasmPrinter::printModule(&module, o);
-}
-
-inline std::ostream& operator<<(std::ostream& o, wasm::Expression& expression) {
-  return wasm::WasmPrinter::printExpression(&expression, o);
-}
-
-inline std::ostream& operator<<(std::ostream& o, wasm::Expression* expression) {
-  return wasm::WasmPrinter::printExpression(expression, o);
-}
-
-inline std::ostream& operator<<(std::ostream& o, wasm::StackInst& inst) {
-  return wasm::WasmPrinter::printStackInst(&inst, o);
-}
-
-inline std::ostream& operator<<(std::ostream& o, wasm::StackIR& ir) {
-  return wasm::WasmPrinter::printStackIR(&ir, o);
-}
-
-} // namespace std
-
-#endif // wasm_wasm_printing_h
diff --git a/binaryen/src/wasm-s-parser.h b/binaryen/src/wasm-s-parser.h
--- a/binaryen/src/wasm-s-parser.h
+++ b/binaryen/src/wasm-s-parser.h
@@ -77,6 +77,11 @@
   Element* setString(cashew::IString str__, bool dollared__, bool quoted__);
   Element* setMetadata(size_t line_, size_t col_, SourceLocation* startLoc_);
 
+  // comparisons
+  bool operator==(Name name) { return isStr() && str() == name; }
+
+  template<typename T> bool operator!=(T t) { return !(*this == t); }
+
   // printing
   friend std::ostream& operator<<(std::ostream& o, Element& e);
   void dump();
@@ -112,16 +117,21 @@
   Module& wasm;
   MixedArena& allocator;
   IRProfile profile;
-  std::vector<Signature> signatures;
-  std::unordered_map<std::string, size_t> signatureIndices;
+
+  // The main list of types declared in the module
+  std::vector<HeapType> types;
+  std::unordered_map<std::string, size_t> typeIndices;
+
   std::vector<Name> functionNames;
   std::vector<Name> globalNames;
   std::vector<Name> eventNames;
   int functionCounter = 0;
   int globalCounter = 0;
   int eventCounter = 0;
+  int tableCounter = 0;
+  int memoryCounter = 0;
   // we need to know function return types before we parse their contents
-  std::map<Name, Type> functionTypes;
+  std::map<Name, Signature> functionSignatures;
   std::unordered_map<cashew::IString, Index> debugInfoFileIndices;
 
 public:
@@ -142,7 +152,6 @@
 
   UniqueNameMapper nameMapper;
 
-  Signature getFunctionSignature(Element& s);
   Name getFunctionName(Element& s);
   Name getGlobalName(Element& s);
   Name getEventName(Element& s);
@@ -210,6 +219,8 @@
   Expression* makeSIMDTernary(Element& s, SIMDTernaryOp op);
   Expression* makeSIMDShift(Element& s, SIMDShiftOp op);
   Expression* makeSIMDLoad(Element& s, SIMDLoadOp op);
+  Expression* makeSIMDLoadStoreLane(Element& s, SIMDLoadStoreLaneOp op);
+  Expression* makePrefetch(Element& s, PrefetchOp op);
   Expression* makeMemoryInit(Element& s);
   Expression* makeDataDrop(Element& s);
   Expression* makeMemoryCopy(Element& s);
@@ -243,6 +254,7 @@
   Expression* makeBrOnExn(Element& s);
   Expression* makeTupleMake(Element& s);
   Expression* makeTupleExtract(Element& s);
+  Expression* makeCallRef(Element& s, bool isReturn);
   Expression* makeI31New(Element& s);
   Expression* makeI31Get(Element& s, bool signed_);
   Expression* makeRefTest(Element& s);
@@ -251,12 +263,11 @@
   Expression* makeRttCanon(Element& s);
   Expression* makeRttSub(Element& s);
   Expression* makeStructNew(Element& s, bool default_);
-  Expression* makeStructGet(Element& s);
-  Expression* makeStructGet(Element& s, bool signed_);
+  Index getStructIndex(const HeapType& type, Element& s);
+  Expression* makeStructGet(Element& s, bool signed_ = false);
   Expression* makeStructSet(Element& s);
   Expression* makeArrayNew(Element& s, bool default_);
-  Expression* makeArrayGet(Element& s);
-  Expression* makeArrayGet(Element& s, bool signed_);
+  Expression* makeArrayGet(Element& s, bool signed_ = false);
   Expression* makeArraySet(Element& s);
   Expression* makeArrayLen(Element& s);
 
@@ -278,17 +289,30 @@
   void stringToBinary(const char* input, size_t size, std::vector<char>& data);
   void parseMemory(Element& s, bool preParseImport = false);
   void parseData(Element& s);
-  void parseInnerData(Element& s, Index i, Expression* offset, bool isPassive);
+  void parseInnerData(
+    Element& s, Index i, Name name, Expression* offset, bool isPassive);
   void parseExport(Element& s);
   void parseImport(Element& s);
   void parseGlobal(Element& s, bool preParseImport = false);
   void parseTable(Element& s, bool preParseImport = false);
   void parseElem(Element& s);
   void parseInnerElem(Element& s, Index i = 1, Expression* offset = nullptr);
+
+  // Parses something like (func ..), (array ..), (struct)
+  HeapType parseHeapType(Element& s);
+
   void parseType(Element& s);
   void parseEvent(Element& s, bool preParseImport = false);
 
   Function::DebugLocation getDebugLocation(const SourceLocation& loc);
+
+  // Struct/Array instructions have an unnecessary heap type that is just for
+  // validation (except for the case of unreachability, but that's not a problem
+  // anyhow, we can ignore it there). That is, we also have a reference / rtt
+  // child from which we can infer the type anyhow, and we just need to check
+  // that type is the same.
+  void
+  validateHeapTypeUsingChild(Expression* child, HeapType heapType, Element& s);
 };
 
 } // namespace wasm
diff --git a/binaryen/src/wasm-stack.h b/binaryen/src/wasm-stack.h
--- a/binaryen/src/wasm-stack.h
+++ b/binaryen/src/wasm-stack.h
@@ -99,69 +99,10 @@
     }
   }
 
-  void visitBlock(Block* curr);
-  void visitIf(If* curr);
-  void visitLoop(Loop* curr);
-  void visitBreak(Break* curr);
-  void visitSwitch(Switch* curr);
-  void visitCall(Call* curr);
-  void visitCallIndirect(CallIndirect* curr);
-  void visitLocalGet(LocalGet* curr);
-  void visitLocalSet(LocalSet* curr);
-  void visitGlobalGet(GlobalGet* curr);
-  void visitGlobalSet(GlobalSet* curr);
-  void visitLoad(Load* curr);
-  void visitStore(Store* curr);
-  void visitAtomicRMW(AtomicRMW* curr);
-  void visitAtomicCmpxchg(AtomicCmpxchg* curr);
-  void visitAtomicWait(AtomicWait* curr);
-  void visitAtomicNotify(AtomicNotify* curr);
-  void visitAtomicFence(AtomicFence* curr);
-  void visitSIMDExtract(SIMDExtract* curr);
-  void visitSIMDReplace(SIMDReplace* curr);
-  void visitSIMDShuffle(SIMDShuffle* curr);
-  void visitSIMDTernary(SIMDTernary* curr);
-  void visitSIMDShift(SIMDShift* curr);
-  void visitSIMDLoad(SIMDLoad* curr);
-  void visitMemoryInit(MemoryInit* curr);
-  void visitDataDrop(DataDrop* curr);
-  void visitMemoryCopy(MemoryCopy* curr);
-  void visitMemoryFill(MemoryFill* curr);
-  void visitConst(Const* curr);
-  void visitUnary(Unary* curr);
-  void visitBinary(Binary* curr);
-  void visitSelect(Select* curr);
-  void visitReturn(Return* curr);
-  void visitMemorySize(MemorySize* curr);
-  void visitMemoryGrow(MemoryGrow* curr);
-  void visitRefNull(RefNull* curr);
-  void visitRefIsNull(RefIsNull* curr);
-  void visitRefFunc(RefFunc* curr);
-  void visitRefEq(RefEq* curr);
-  void visitTry(Try* curr);
-  void visitThrow(Throw* curr);
-  void visitRethrow(Rethrow* curr);
-  void visitBrOnExn(BrOnExn* curr);
-  void visitNop(Nop* curr);
-  void visitUnreachable(Unreachable* curr);
-  void visitDrop(Drop* curr);
-  void visitPop(Pop* curr);
-  void visitTupleMake(TupleMake* curr);
-  void visitTupleExtract(TupleExtract* curr);
-  void visitI31New(I31New* curr);
-  void visitI31Get(I31Get* curr);
-  void visitRefTest(RefTest* curr);
-  void visitRefCast(RefCast* curr);
-  void visitBrOnCast(BrOnCast* curr);
-  void visitRttCanon(RttCanon* curr);
-  void visitRttSub(RttSub* curr);
-  void visitStructNew(StructNew* curr);
-  void visitStructGet(StructGet* curr);
-  void visitStructSet(StructSet* curr);
-  void visitArrayNew(ArrayNew* curr);
-  void visitArrayGet(ArrayGet* curr);
-  void visitArraySet(ArraySet* curr);
-  void visitArrayLen(ArrayLen* curr);
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  void visit##CLASS_TO_VISIT(CLASS_TO_VISIT* curr);
+
+#include "wasm-delegations.h"
 
   void emitResultType(Type type);
   void emitIfElse(If* curr);
diff --git a/binaryen/src/wasm-traversal.h b/binaryen/src/wasm-traversal.h
--- a/binaryen/src/wasm-traversal.h
+++ b/binaryen/src/wasm-traversal.h
@@ -37,1373 +37,314 @@
 
 template<typename SubType, typename ReturnType = void> struct Visitor {
   // Expression visitors
-  ReturnType visitBlock(Block* curr) { return ReturnType(); }
-  ReturnType visitIf(If* curr) { return ReturnType(); }
-  ReturnType visitLoop(Loop* curr) { return ReturnType(); }
-  ReturnType visitBreak(Break* curr) { return ReturnType(); }
-  ReturnType visitSwitch(Switch* curr) { return ReturnType(); }
-  ReturnType visitCall(Call* curr) { return ReturnType(); }
-  ReturnType visitCallIndirect(CallIndirect* curr) { return ReturnType(); }
-  ReturnType visitLocalGet(LocalGet* curr) { return ReturnType(); }
-  ReturnType visitLocalSet(LocalSet* curr) { return ReturnType(); }
-  ReturnType visitGlobalGet(GlobalGet* curr) { return ReturnType(); }
-  ReturnType visitGlobalSet(GlobalSet* curr) { return ReturnType(); }
-  ReturnType visitLoad(Load* curr) { return ReturnType(); }
-  ReturnType visitStore(Store* curr) { return ReturnType(); }
-  ReturnType visitAtomicRMW(AtomicRMW* curr) { return ReturnType(); }
-  ReturnType visitAtomicCmpxchg(AtomicCmpxchg* curr) { return ReturnType(); }
-  ReturnType visitAtomicWait(AtomicWait* curr) { return ReturnType(); }
-  ReturnType visitAtomicNotify(AtomicNotify* curr) { return ReturnType(); }
-  ReturnType visitAtomicFence(AtomicFence* curr) { return ReturnType(); }
-  ReturnType visitSIMDExtract(SIMDExtract* curr) { return ReturnType(); }
-  ReturnType visitSIMDReplace(SIMDReplace* curr) { return ReturnType(); }
-  ReturnType visitSIMDShuffle(SIMDShuffle* curr) { return ReturnType(); }
-  ReturnType visitSIMDTernary(SIMDTernary* curr) { return ReturnType(); }
-  ReturnType visitSIMDShift(SIMDShift* curr) { return ReturnType(); }
-  ReturnType visitSIMDLoad(SIMDLoad* curr) { return ReturnType(); }
-  ReturnType visitMemoryInit(MemoryInit* curr) { return ReturnType(); }
-  ReturnType visitDataDrop(DataDrop* curr) { return ReturnType(); }
-  ReturnType visitMemoryCopy(MemoryCopy* curr) { return ReturnType(); }
-  ReturnType visitMemoryFill(MemoryFill* curr) { return ReturnType(); }
-  ReturnType visitConst(Const* curr) { return ReturnType(); }
-  ReturnType visitUnary(Unary* curr) { return ReturnType(); }
-  ReturnType visitBinary(Binary* curr) { return ReturnType(); }
-  ReturnType visitSelect(Select* curr) { return ReturnType(); }
-  ReturnType visitDrop(Drop* curr) { return ReturnType(); }
-  ReturnType visitReturn(Return* curr) { return ReturnType(); }
-  ReturnType visitMemorySize(MemorySize* curr) { return ReturnType(); }
-  ReturnType visitMemoryGrow(MemoryGrow* curr) { return ReturnType(); }
-  ReturnType visitRefNull(RefNull* curr) { return ReturnType(); }
-  ReturnType visitRefIsNull(RefIsNull* curr) { return ReturnType(); }
-  ReturnType visitRefFunc(RefFunc* curr) { return ReturnType(); }
-  ReturnType visitRefEq(RefEq* curr) { return ReturnType(); }
-  ReturnType visitTry(Try* curr) { return ReturnType(); }
-  ReturnType visitThrow(Throw* curr) { return ReturnType(); }
-  ReturnType visitRethrow(Rethrow* curr) { return ReturnType(); }
-  ReturnType visitBrOnExn(BrOnExn* curr) { return ReturnType(); }
-  ReturnType visitNop(Nop* curr) { return ReturnType(); }
-  ReturnType visitUnreachable(Unreachable* curr) { return ReturnType(); }
-  ReturnType visitPop(Pop* curr) { return ReturnType(); }
-  ReturnType visitTupleMake(TupleMake* curr) { return ReturnType(); }
-  ReturnType visitTupleExtract(TupleExtract* curr) { return ReturnType(); }
-  ReturnType visitI31New(I31New* curr) { return ReturnType(); }
-  ReturnType visitI31Get(I31Get* curr) { return ReturnType(); }
-  ReturnType visitRefTest(RefTest* curr) { return ReturnType(); }
-  ReturnType visitRefCast(RefCast* curr) { return ReturnType(); }
-  ReturnType visitBrOnCast(BrOnCast* curr) { return ReturnType(); }
-  ReturnType visitRttCanon(RttCanon* curr) { return ReturnType(); }
-  ReturnType visitRttSub(RttSub* curr) { return ReturnType(); }
-  ReturnType visitStructNew(StructNew* curr) { return ReturnType(); }
-  ReturnType visitStructGet(StructGet* curr) { return ReturnType(); }
-  ReturnType visitStructSet(StructSet* curr) { return ReturnType(); }
-  ReturnType visitArrayNew(ArrayNew* curr) { return ReturnType(); }
-  ReturnType visitArrayGet(ArrayGet* curr) { return ReturnType(); }
-  ReturnType visitArraySet(ArraySet* curr) { return ReturnType(); }
-  ReturnType visitArrayLen(ArrayLen* curr) { return ReturnType(); }
-  // Module-level visitors
-  ReturnType visitExport(Export* curr) { return ReturnType(); }
-  ReturnType visitGlobal(Global* curr) { return ReturnType(); }
-  ReturnType visitFunction(Function* curr) { return ReturnType(); }
-  ReturnType visitTable(Table* curr) { return ReturnType(); }
-  ReturnType visitMemory(Memory* curr) { return ReturnType(); }
-  ReturnType visitEvent(Event* curr) { return ReturnType(); }
-  ReturnType visitModule(Module* curr) { return ReturnType(); }
-
-  ReturnType visit(Expression* curr) {
-    assert(curr);
-
-#define DELEGATE(CLASS_TO_VISIT)                                               \
-  return static_cast<SubType*>(this)->visit##CLASS_TO_VISIT(                   \
-    static_cast<CLASS_TO_VISIT*>(curr))
-
-    switch (curr->_id) {
-      case Expression::Id::BlockId:
-        DELEGATE(Block);
-      case Expression::Id::IfId:
-        DELEGATE(If);
-      case Expression::Id::LoopId:
-        DELEGATE(Loop);
-      case Expression::Id::BreakId:
-        DELEGATE(Break);
-      case Expression::Id::SwitchId:
-        DELEGATE(Switch);
-      case Expression::Id::CallId:
-        DELEGATE(Call);
-      case Expression::Id::CallIndirectId:
-        DELEGATE(CallIndirect);
-      case Expression::Id::LocalGetId:
-        DELEGATE(LocalGet);
-      case Expression::Id::LocalSetId:
-        DELEGATE(LocalSet);
-      case Expression::Id::GlobalGetId:
-        DELEGATE(GlobalGet);
-      case Expression::Id::GlobalSetId:
-        DELEGATE(GlobalSet);
-      case Expression::Id::LoadId:
-        DELEGATE(Load);
-      case Expression::Id::StoreId:
-        DELEGATE(Store);
-      case Expression::Id::AtomicRMWId:
-        DELEGATE(AtomicRMW);
-      case Expression::Id::AtomicCmpxchgId:
-        DELEGATE(AtomicCmpxchg);
-      case Expression::Id::AtomicWaitId:
-        DELEGATE(AtomicWait);
-      case Expression::Id::AtomicNotifyId:
-        DELEGATE(AtomicNotify);
-      case Expression::Id::AtomicFenceId:
-        DELEGATE(AtomicFence);
-      case Expression::Id::SIMDExtractId:
-        DELEGATE(SIMDExtract);
-      case Expression::Id::SIMDReplaceId:
-        DELEGATE(SIMDReplace);
-      case Expression::Id::SIMDShuffleId:
-        DELEGATE(SIMDShuffle);
-      case Expression::Id::SIMDTernaryId:
-        DELEGATE(SIMDTernary);
-      case Expression::Id::SIMDShiftId:
-        DELEGATE(SIMDShift);
-      case Expression::Id::SIMDLoadId:
-        DELEGATE(SIMDLoad);
-      case Expression::Id::MemoryInitId:
-        DELEGATE(MemoryInit);
-      case Expression::Id::DataDropId:
-        DELEGATE(DataDrop);
-      case Expression::Id::MemoryCopyId:
-        DELEGATE(MemoryCopy);
-      case Expression::Id::MemoryFillId:
-        DELEGATE(MemoryFill);
-      case Expression::Id::ConstId:
-        DELEGATE(Const);
-      case Expression::Id::UnaryId:
-        DELEGATE(Unary);
-      case Expression::Id::BinaryId:
-        DELEGATE(Binary);
-      case Expression::Id::SelectId:
-        DELEGATE(Select);
-      case Expression::Id::DropId:
-        DELEGATE(Drop);
-      case Expression::Id::ReturnId:
-        DELEGATE(Return);
-      case Expression::Id::MemorySizeId:
-        DELEGATE(MemorySize);
-      case Expression::Id::MemoryGrowId:
-        DELEGATE(MemoryGrow);
-      case Expression::Id::RefNullId:
-        DELEGATE(RefNull);
-      case Expression::Id::RefIsNullId:
-        DELEGATE(RefIsNull);
-      case Expression::Id::RefFuncId:
-        DELEGATE(RefFunc);
-      case Expression::Id::RefEqId:
-        DELEGATE(RefEq);
-      case Expression::Id::TryId:
-        DELEGATE(Try);
-      case Expression::Id::ThrowId:
-        DELEGATE(Throw);
-      case Expression::Id::RethrowId:
-        DELEGATE(Rethrow);
-      case Expression::Id::BrOnExnId:
-        DELEGATE(BrOnExn);
-      case Expression::Id::NopId:
-        DELEGATE(Nop);
-      case Expression::Id::UnreachableId:
-        DELEGATE(Unreachable);
-      case Expression::Id::PopId:
-        DELEGATE(Pop);
-      case Expression::Id::TupleMakeId:
-        DELEGATE(TupleMake);
-      case Expression::Id::TupleExtractId:
-        DELEGATE(TupleExtract);
-      case Expression::Id::I31NewId:
-        DELEGATE(I31New);
-      case Expression::Id::I31GetId:
-        DELEGATE(I31Get);
-      case Expression::Id::RefTestId:
-        DELEGATE(RefTest);
-      case Expression::Id::RefCastId:
-        DELEGATE(RefCast);
-      case Expression::Id::BrOnCastId:
-        DELEGATE(BrOnCast);
-      case Expression::Id::RttCanonId:
-        DELEGATE(RttCanon);
-      case Expression::Id::RttSubId:
-        DELEGATE(RttSub);
-      case Expression::Id::StructNewId:
-        DELEGATE(StructNew);
-      case Expression::Id::StructGetId:
-        DELEGATE(StructGet);
-      case Expression::Id::StructSetId:
-        DELEGATE(StructSet);
-      case Expression::Id::ArrayNewId:
-        DELEGATE(ArrayNew);
-      case Expression::Id::ArrayGetId:
-        DELEGATE(ArrayGet);
-      case Expression::Id::ArraySetId:
-        DELEGATE(ArraySet);
-      case Expression::Id::ArrayLenId:
-        DELEGATE(ArrayLen);
-      case Expression::Id::InvalidId:
-      default:
-        WASM_UNREACHABLE("unexpected expression type");
-    }
-
-#undef DELEGATE
-  }
-};
-
-// A visitor which must be overridden for each visitor that is reached.
-
-template<typename SubType, typename ReturnType = void>
-struct OverriddenVisitor {
-// Expression visitors, which must be overridden
-#define UNIMPLEMENTED(CLASS_TO_VISIT)                                          \
-  ReturnType visit##CLASS_TO_VISIT(CLASS_TO_VISIT* curr) {                     \
-    static_assert(                                                             \
-      &SubType::visit##CLASS_TO_VISIT !=                                       \
-        &OverriddenVisitor<SubType, ReturnType>::visit##CLASS_TO_VISIT,        \
-      "Derived class must implement visit" #CLASS_TO_VISIT);                   \
-    WASM_UNREACHABLE("Derived class must implement visit" #CLASS_TO_VISIT);    \
-  }
-
-  UNIMPLEMENTED(Block);
-  UNIMPLEMENTED(If);
-  UNIMPLEMENTED(Loop);
-  UNIMPLEMENTED(Break);
-  UNIMPLEMENTED(Switch);
-  UNIMPLEMENTED(Call);
-  UNIMPLEMENTED(CallIndirect);
-  UNIMPLEMENTED(LocalGet);
-  UNIMPLEMENTED(LocalSet);
-  UNIMPLEMENTED(GlobalGet);
-  UNIMPLEMENTED(GlobalSet);
-  UNIMPLEMENTED(Load);
-  UNIMPLEMENTED(Store);
-  UNIMPLEMENTED(AtomicRMW);
-  UNIMPLEMENTED(AtomicCmpxchg);
-  UNIMPLEMENTED(AtomicWait);
-  UNIMPLEMENTED(AtomicNotify);
-  UNIMPLEMENTED(AtomicFence);
-  UNIMPLEMENTED(SIMDExtract);
-  UNIMPLEMENTED(SIMDReplace);
-  UNIMPLEMENTED(SIMDShuffle);
-  UNIMPLEMENTED(SIMDTernary);
-  UNIMPLEMENTED(SIMDShift);
-  UNIMPLEMENTED(SIMDLoad);
-  UNIMPLEMENTED(MemoryInit);
-  UNIMPLEMENTED(DataDrop);
-  UNIMPLEMENTED(MemoryCopy);
-  UNIMPLEMENTED(MemoryFill);
-  UNIMPLEMENTED(Const);
-  UNIMPLEMENTED(Unary);
-  UNIMPLEMENTED(Binary);
-  UNIMPLEMENTED(Select);
-  UNIMPLEMENTED(Drop);
-  UNIMPLEMENTED(Return);
-  UNIMPLEMENTED(MemorySize);
-  UNIMPLEMENTED(MemoryGrow);
-  UNIMPLEMENTED(RefNull);
-  UNIMPLEMENTED(RefIsNull);
-  UNIMPLEMENTED(RefFunc);
-  UNIMPLEMENTED(RefEq);
-  UNIMPLEMENTED(Try);
-  UNIMPLEMENTED(Throw);
-  UNIMPLEMENTED(Rethrow);
-  UNIMPLEMENTED(BrOnExn);
-  UNIMPLEMENTED(Nop);
-  UNIMPLEMENTED(Unreachable);
-  UNIMPLEMENTED(Pop);
-  UNIMPLEMENTED(TupleMake);
-  UNIMPLEMENTED(TupleExtract);
-  UNIMPLEMENTED(I31New);
-  UNIMPLEMENTED(I31Get);
-  UNIMPLEMENTED(RefTest);
-  UNIMPLEMENTED(RefCast);
-  UNIMPLEMENTED(BrOnCast);
-  UNIMPLEMENTED(RttCanon);
-  UNIMPLEMENTED(RttSub);
-  UNIMPLEMENTED(StructNew);
-  UNIMPLEMENTED(StructGet);
-  UNIMPLEMENTED(StructSet);
-  UNIMPLEMENTED(ArrayNew);
-  UNIMPLEMENTED(ArrayGet);
-  UNIMPLEMENTED(ArraySet);
-  UNIMPLEMENTED(ArrayLen);
-  UNIMPLEMENTED(Export);
-  UNIMPLEMENTED(Global);
-  UNIMPLEMENTED(Function);
-  UNIMPLEMENTED(Table);
-  UNIMPLEMENTED(Memory);
-  UNIMPLEMENTED(Event);
-  UNIMPLEMENTED(Module);
-
-#undef UNIMPLEMENTED
-
-  ReturnType visit(Expression* curr) {
-    assert(curr);
-
-#define DELEGATE(CLASS_TO_VISIT)                                               \
-  return static_cast<SubType*>(this)->visit##CLASS_TO_VISIT(                   \
-    static_cast<CLASS_TO_VISIT*>(curr))
-
-    switch (curr->_id) {
-      case Expression::Id::BlockId:
-        DELEGATE(Block);
-      case Expression::Id::IfId:
-        DELEGATE(If);
-      case Expression::Id::LoopId:
-        DELEGATE(Loop);
-      case Expression::Id::BreakId:
-        DELEGATE(Break);
-      case Expression::Id::SwitchId:
-        DELEGATE(Switch);
-      case Expression::Id::CallId:
-        DELEGATE(Call);
-      case Expression::Id::CallIndirectId:
-        DELEGATE(CallIndirect);
-      case Expression::Id::LocalGetId:
-        DELEGATE(LocalGet);
-      case Expression::Id::LocalSetId:
-        DELEGATE(LocalSet);
-      case Expression::Id::GlobalGetId:
-        DELEGATE(GlobalGet);
-      case Expression::Id::GlobalSetId:
-        DELEGATE(GlobalSet);
-      case Expression::Id::LoadId:
-        DELEGATE(Load);
-      case Expression::Id::StoreId:
-        DELEGATE(Store);
-      case Expression::Id::AtomicRMWId:
-        DELEGATE(AtomicRMW);
-      case Expression::Id::AtomicCmpxchgId:
-        DELEGATE(AtomicCmpxchg);
-      case Expression::Id::AtomicWaitId:
-        DELEGATE(AtomicWait);
-      case Expression::Id::AtomicNotifyId:
-        DELEGATE(AtomicNotify);
-      case Expression::Id::AtomicFenceId:
-        DELEGATE(AtomicFence);
-      case Expression::Id::SIMDExtractId:
-        DELEGATE(SIMDExtract);
-      case Expression::Id::SIMDReplaceId:
-        DELEGATE(SIMDReplace);
-      case Expression::Id::SIMDShuffleId:
-        DELEGATE(SIMDShuffle);
-      case Expression::Id::SIMDTernaryId:
-        DELEGATE(SIMDTernary);
-      case Expression::Id::SIMDShiftId:
-        DELEGATE(SIMDShift);
-      case Expression::Id::SIMDLoadId:
-        DELEGATE(SIMDLoad);
-      case Expression::Id::MemoryInitId:
-        DELEGATE(MemoryInit);
-      case Expression::Id::DataDropId:
-        DELEGATE(DataDrop);
-      case Expression::Id::MemoryCopyId:
-        DELEGATE(MemoryCopy);
-      case Expression::Id::MemoryFillId:
-        DELEGATE(MemoryFill);
-      case Expression::Id::ConstId:
-        DELEGATE(Const);
-      case Expression::Id::UnaryId:
-        DELEGATE(Unary);
-      case Expression::Id::BinaryId:
-        DELEGATE(Binary);
-      case Expression::Id::SelectId:
-        DELEGATE(Select);
-      case Expression::Id::DropId:
-        DELEGATE(Drop);
-      case Expression::Id::ReturnId:
-        DELEGATE(Return);
-      case Expression::Id::MemorySizeId:
-        DELEGATE(MemorySize);
-      case Expression::Id::MemoryGrowId:
-        DELEGATE(MemoryGrow);
-      case Expression::Id::RefNullId:
-        DELEGATE(RefNull);
-      case Expression::Id::RefIsNullId:
-        DELEGATE(RefIsNull);
-      case Expression::Id::RefFuncId:
-        DELEGATE(RefFunc);
-      case Expression::Id::RefEqId:
-        DELEGATE(RefEq);
-      case Expression::Id::TryId:
-        DELEGATE(Try);
-      case Expression::Id::ThrowId:
-        DELEGATE(Throw);
-      case Expression::Id::RethrowId:
-        DELEGATE(Rethrow);
-      case Expression::Id::BrOnExnId:
-        DELEGATE(BrOnExn);
-      case Expression::Id::NopId:
-        DELEGATE(Nop);
-      case Expression::Id::UnreachableId:
-        DELEGATE(Unreachable);
-      case Expression::Id::PopId:
-        DELEGATE(Pop);
-      case Expression::Id::TupleMakeId:
-        DELEGATE(TupleMake);
-      case Expression::Id::TupleExtractId:
-        DELEGATE(TupleExtract);
-      case Expression::Id::I31NewId:
-        DELEGATE(I31New);
-      case Expression::Id::I31GetId:
-        DELEGATE(I31Get);
-      case Expression::Id::RefTestId:
-        DELEGATE(RefTest);
-      case Expression::Id::RefCastId:
-        DELEGATE(RefCast);
-      case Expression::Id::BrOnCastId:
-        DELEGATE(BrOnCast);
-      case Expression::Id::RttCanonId:
-        DELEGATE(RttCanon);
-      case Expression::Id::RttSubId:
-        DELEGATE(RttSub);
-      case Expression::Id::StructNewId:
-        DELEGATE(StructNew);
-      case Expression::Id::StructGetId:
-        DELEGATE(StructGet);
-      case Expression::Id::StructSetId:
-        DELEGATE(StructSet);
-      case Expression::Id::ArrayNewId:
-        DELEGATE(ArrayNew);
-      case Expression::Id::ArrayGetId:
-        DELEGATE(ArrayGet);
-      case Expression::Id::ArraySetId:
-        DELEGATE(ArraySet);
-      case Expression::Id::ArrayLenId:
-        DELEGATE(ArrayLen);
-      case Expression::Id::InvalidId:
-      default:
-        WASM_UNREACHABLE("unexpected expression type");
-    }
-
-#undef DELEGATE
-  }
-};
-
-// Visit with a single unified visitor, called on every node, instead of
-// separate visit* per node
-
-template<typename SubType, typename ReturnType = void>
-struct UnifiedExpressionVisitor : public Visitor<SubType, ReturnType> {
-  // called on each node
-  ReturnType visitExpression(Expression* curr) { return ReturnType(); }
-
-  // redirects
-  ReturnType visitBlock(Block* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitIf(If* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitLoop(Loop* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitBreak(Break* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitSwitch(Switch* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitCall(Call* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitCallIndirect(CallIndirect* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitLocalGet(LocalGet* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitLocalSet(LocalSet* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitGlobalGet(GlobalGet* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitGlobalSet(GlobalSet* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitLoad(Load* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitStore(Store* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitAtomicRMW(AtomicRMW* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitAtomicCmpxchg(AtomicCmpxchg* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitAtomicWait(AtomicWait* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitAtomicNotify(AtomicNotify* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitAtomicFence(AtomicFence* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitSIMDExtract(SIMDExtract* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitSIMDReplace(SIMDReplace* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitSIMDShuffle(SIMDShuffle* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitSIMDTernary(SIMDTernary* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitSIMDShift(SIMDShift* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitSIMDLoad(SIMDLoad* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitMemoryInit(MemoryInit* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitDataDrop(DataDrop* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitMemoryCopy(MemoryCopy* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitMemoryFill(MemoryFill* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitConst(Const* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitUnary(Unary* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitBinary(Binary* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitSelect(Select* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitDrop(Drop* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitReturn(Return* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitMemorySize(MemorySize* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitMemoryGrow(MemoryGrow* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitRefNull(RefNull* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitRefIsNull(RefIsNull* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitRefFunc(RefFunc* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitRefEq(RefEq* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitTry(Try* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitThrow(Throw* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitRethrow(Rethrow* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitBrOnExn(BrOnExn* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitNop(Nop* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitUnreachable(Unreachable* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitPop(Pop* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitTupleMake(TupleMake* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitTupleExtract(TupleExtract* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitI31New(I31New* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitI31Get(I31Get* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitRefTest(RefTest* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitRefCast(RefCast* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitBrOnCast(BrOnCast* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitRttCanon(RttCanon* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitRttSub(RttSub* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitStructNew(StructNew* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitStructGet(StructGet* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitStructSet(StructSet* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitArrayNew(ArrayNew* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitArrayGet(ArrayGet* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitArraySet(ArraySet* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-  ReturnType visitArrayLen(ArrayLen* curr) {
-    return static_cast<SubType*>(this)->visitExpression(curr);
-  }
-};
-
-//
-// Base class for all WasmWalkers, which can traverse an AST
-// and provide the option to replace nodes while doing so.
-//
-// Subclass and implement the visit*()
-// calls to run code on different node types.
-//
-template<typename SubType, typename VisitorType>
-struct Walker : public VisitorType {
-  // Useful methods for visitor implementions
-
-  // Replace the current node. You can call this in your visit*() methods.
-  // Note that the visit*() for the result node is not called for you (i.e.,
-  // just one visit*() method is called by the traversal; if you replace a node,
-  // and you want to process the output, you must do that explicitly).
-  Expression* replaceCurrent(Expression* expression) {
-    // Copy debug info, if present.
-    if (currFunction) {
-      auto& debugLocations = currFunction->debugLocations;
-      if (!debugLocations.empty()) {
-        auto* curr = getCurrent();
-        auto iter = debugLocations.find(curr);
-        if (iter != debugLocations.end()) {
-          auto location = iter->second;
-          debugLocations.erase(iter);
-          debugLocations[expression] = location;
-        }
-      }
-    }
-    return *replacep = expression;
-  }
-
-  Expression* getCurrent() { return *replacep; }
-
-  Expression** getCurrentPointer() { return replacep; }
-
-  // Get the current module
-  Module* getModule() { return currModule; }
-
-  // Get the current function
-  Function* getFunction() { return currFunction; }
-
-  // Walk starting
-
-  void walkGlobal(Global* global) {
-    walk(global->init);
-    static_cast<SubType*>(this)->visitGlobal(global);
-  }
-
-  void walkFunction(Function* func) {
-    setFunction(func);
-    static_cast<SubType*>(this)->doWalkFunction(func);
-    static_cast<SubType*>(this)->visitFunction(func);
-    setFunction(nullptr);
-  }
-
-  void walkEvent(Event* event) {
-    static_cast<SubType*>(this)->visitEvent(event);
-  }
-
-  void walkFunctionInModule(Function* func, Module* module) {
-    setModule(module);
-    setFunction(func);
-    static_cast<SubType*>(this)->doWalkFunction(func);
-    static_cast<SubType*>(this)->visitFunction(func);
-    setFunction(nullptr);
-    setModule(nullptr);
-  }
-
-  // override this to provide custom functionality
-  void doWalkFunction(Function* func) { walk(func->body); }
-
-  void walkTable(Table* table) {
-    for (auto& segment : table->segments) {
-      walk(segment.offset);
-    }
-    static_cast<SubType*>(this)->visitTable(table);
-  }
-
-  void walkMemory(Memory* memory) {
-    for (auto& segment : memory->segments) {
-      if (!segment.isPassive) {
-        walk(segment.offset);
-      }
-    }
-    static_cast<SubType*>(this)->visitMemory(memory);
-  }
-
-  void walkModule(Module* module) {
-    setModule(module);
-    static_cast<SubType*>(this)->doWalkModule(module);
-    static_cast<SubType*>(this)->visitModule(module);
-    setModule(nullptr);
-  }
-
-  // override this to provide custom functionality
-  void doWalkModule(Module* module) {
-    // Dispatch statically through the SubType.
-    SubType* self = static_cast<SubType*>(this);
-    for (auto& curr : module->exports) {
-      self->visitExport(curr.get());
-    }
-    for (auto& curr : module->globals) {
-      if (curr->imported()) {
-        self->visitGlobal(curr.get());
-      } else {
-        self->walkGlobal(curr.get());
-      }
-    }
-    for (auto& curr : module->functions) {
-      if (curr->imported()) {
-        self->visitFunction(curr.get());
-      } else {
-        self->walkFunction(curr.get());
-      }
-    }
-    for (auto& curr : module->events) {
-      if (curr->imported()) {
-        self->visitEvent(curr.get());
-      } else {
-        self->walkEvent(curr.get());
-      }
-    }
-    self->walkTable(&module->table);
-    self->walkMemory(&module->memory);
-  }
-
-  // Walk implementation. We don't use recursion as ASTs may be highly
-  // nested.
-
-  // Tasks receive the this pointer and a pointer to the pointer to operate on
-  typedef void (*TaskFunc)(SubType*, Expression**);
-
-  struct Task {
-    TaskFunc func;
-    Expression** currp;
-    Task() {}
-    Task(TaskFunc func, Expression** currp) : func(func), currp(currp) {}
-  };
-
-  void pushTask(TaskFunc func, Expression** currp) {
-    assert(*currp);
-    stack.emplace_back(func, currp);
-  }
-  void maybePushTask(TaskFunc func, Expression** currp) {
-    if (*currp) {
-      stack.emplace_back(func, currp);
-    }
-  }
-  Task popTask() {
-    auto ret = stack.back();
-    stack.pop_back();
-    return ret;
-  }
-
-  void walk(Expression*& root) {
-    assert(stack.size() == 0);
-    pushTask(SubType::scan, &root);
-    while (stack.size() > 0) {
-      auto task = popTask();
-      replacep = task.currp;
-      assert(*task.currp);
-      task.func(static_cast<SubType*>(this), task.currp);
-    }
-  }
-
-  // subclasses implement this to define the proper order of execution
-  static void scan(SubType* self, Expression** currp) { abort(); }
-
-  // task hooks to call visitors
-
-  static void doVisitBlock(SubType* self, Expression** currp) {
-    self->visitBlock((*currp)->cast<Block>());
-  }
-  static void doVisitIf(SubType* self, Expression** currp) {
-    self->visitIf((*currp)->cast<If>());
-  }
-  static void doVisitLoop(SubType* self, Expression** currp) {
-    self->visitLoop((*currp)->cast<Loop>());
-  }
-  static void doVisitBreak(SubType* self, Expression** currp) {
-    self->visitBreak((*currp)->cast<Break>());
-  }
-  static void doVisitSwitch(SubType* self, Expression** currp) {
-    self->visitSwitch((*currp)->cast<Switch>());
-  }
-  static void doVisitCall(SubType* self, Expression** currp) {
-    self->visitCall((*currp)->cast<Call>());
-  }
-  static void doVisitCallIndirect(SubType* self, Expression** currp) {
-    self->visitCallIndirect((*currp)->cast<CallIndirect>());
-  }
-  static void doVisitLocalGet(SubType* self, Expression** currp) {
-    self->visitLocalGet((*currp)->cast<LocalGet>());
-  }
-  static void doVisitLocalSet(SubType* self, Expression** currp) {
-    self->visitLocalSet((*currp)->cast<LocalSet>());
-  }
-  static void doVisitGlobalGet(SubType* self, Expression** currp) {
-    self->visitGlobalGet((*currp)->cast<GlobalGet>());
-  }
-  static void doVisitGlobalSet(SubType* self, Expression** currp) {
-    self->visitGlobalSet((*currp)->cast<GlobalSet>());
-  }
-  static void doVisitLoad(SubType* self, Expression** currp) {
-    self->visitLoad((*currp)->cast<Load>());
-  }
-  static void doVisitStore(SubType* self, Expression** currp) {
-    self->visitStore((*currp)->cast<Store>());
-  }
-  static void doVisitAtomicRMW(SubType* self, Expression** currp) {
-    self->visitAtomicRMW((*currp)->cast<AtomicRMW>());
-  }
-  static void doVisitAtomicCmpxchg(SubType* self, Expression** currp) {
-    self->visitAtomicCmpxchg((*currp)->cast<AtomicCmpxchg>());
-  }
-  static void doVisitAtomicWait(SubType* self, Expression** currp) {
-    self->visitAtomicWait((*currp)->cast<AtomicWait>());
-  }
-  static void doVisitAtomicNotify(SubType* self, Expression** currp) {
-    self->visitAtomicNotify((*currp)->cast<AtomicNotify>());
-  }
-  static void doVisitAtomicFence(SubType* self, Expression** currp) {
-    self->visitAtomicFence((*currp)->cast<AtomicFence>());
-  }
-  static void doVisitSIMDExtract(SubType* self, Expression** currp) {
-    self->visitSIMDExtract((*currp)->cast<SIMDExtract>());
-  }
-  static void doVisitSIMDReplace(SubType* self, Expression** currp) {
-    self->visitSIMDReplace((*currp)->cast<SIMDReplace>());
-  }
-  static void doVisitSIMDShuffle(SubType* self, Expression** currp) {
-    self->visitSIMDShuffle((*currp)->cast<SIMDShuffle>());
-  }
-  static void doVisitSIMDTernary(SubType* self, Expression** currp) {
-    self->visitSIMDTernary((*currp)->cast<SIMDTernary>());
-  }
-  static void doVisitSIMDShift(SubType* self, Expression** currp) {
-    self->visitSIMDShift((*currp)->cast<SIMDShift>());
-  }
-  static void doVisitSIMDLoad(SubType* self, Expression** currp) {
-    self->visitSIMDLoad((*currp)->cast<SIMDLoad>());
-  }
-  static void doVisitMemoryInit(SubType* self, Expression** currp) {
-    self->visitMemoryInit((*currp)->cast<MemoryInit>());
-  }
-  static void doVisitDataDrop(SubType* self, Expression** currp) {
-    self->visitDataDrop((*currp)->cast<DataDrop>());
-  }
-  static void doVisitMemoryCopy(SubType* self, Expression** currp) {
-    self->visitMemoryCopy((*currp)->cast<MemoryCopy>());
-  }
-  static void doVisitMemoryFill(SubType* self, Expression** currp) {
-    self->visitMemoryFill((*currp)->cast<MemoryFill>());
-  }
-  static void doVisitConst(SubType* self, Expression** currp) {
-    self->visitConst((*currp)->cast<Const>());
-  }
-  static void doVisitUnary(SubType* self, Expression** currp) {
-    self->visitUnary((*currp)->cast<Unary>());
-  }
-  static void doVisitBinary(SubType* self, Expression** currp) {
-    self->visitBinary((*currp)->cast<Binary>());
-  }
-  static void doVisitSelect(SubType* self, Expression** currp) {
-    self->visitSelect((*currp)->cast<Select>());
-  }
-  static void doVisitDrop(SubType* self, Expression** currp) {
-    self->visitDrop((*currp)->cast<Drop>());
-  }
-  static void doVisitReturn(SubType* self, Expression** currp) {
-    self->visitReturn((*currp)->cast<Return>());
-  }
-  static void doVisitMemorySize(SubType* self, Expression** currp) {
-    self->visitMemorySize((*currp)->cast<MemorySize>());
-  }
-  static void doVisitMemoryGrow(SubType* self, Expression** currp) {
-    self->visitMemoryGrow((*currp)->cast<MemoryGrow>());
-  }
-  static void doVisitRefNull(SubType* self, Expression** currp) {
-    self->visitRefNull((*currp)->cast<RefNull>());
-  }
-  static void doVisitRefIsNull(SubType* self, Expression** currp) {
-    self->visitRefIsNull((*currp)->cast<RefIsNull>());
-  }
-  static void doVisitRefFunc(SubType* self, Expression** currp) {
-    self->visitRefFunc((*currp)->cast<RefFunc>());
-  }
-  static void doVisitRefEq(SubType* self, Expression** currp) {
-    self->visitRefEq((*currp)->cast<RefEq>());
-  }
-  static void doVisitTry(SubType* self, Expression** currp) {
-    self->visitTry((*currp)->cast<Try>());
-  }
-  static void doVisitThrow(SubType* self, Expression** currp) {
-    self->visitThrow((*currp)->cast<Throw>());
-  }
-  static void doVisitRethrow(SubType* self, Expression** currp) {
-    self->visitRethrow((*currp)->cast<Rethrow>());
-  }
-  static void doVisitBrOnExn(SubType* self, Expression** currp) {
-    self->visitBrOnExn((*currp)->cast<BrOnExn>());
-  }
-  static void doVisitNop(SubType* self, Expression** currp) {
-    self->visitNop((*currp)->cast<Nop>());
-  }
-  static void doVisitUnreachable(SubType* self, Expression** currp) {
-    self->visitUnreachable((*currp)->cast<Unreachable>());
-  }
-  static void doVisitPop(SubType* self, Expression** currp) {
-    self->visitPop((*currp)->cast<Pop>());
-  }
-  static void doVisitTupleMake(SubType* self, Expression** currp) {
-    self->visitTupleMake((*currp)->cast<TupleMake>());
-  }
-  static void doVisitTupleExtract(SubType* self, Expression** currp) {
-    self->visitTupleExtract((*currp)->cast<TupleExtract>());
-  }
-  static void doVisitI31New(SubType* self, Expression** currp) {
-    self->visitI31New((*currp)->cast<I31New>());
-  }
-  static void doVisitI31Get(SubType* self, Expression** currp) {
-    self->visitI31Get((*currp)->cast<I31Get>());
-  }
-  static void doVisitRefTest(SubType* self, Expression** currp) {
-    self->visitRefTest((*currp)->cast<RefTest>());
-  }
-  static void doVisitRefCast(SubType* self, Expression** currp) {
-    self->visitRefCast((*currp)->cast<RefCast>());
-  }
-  static void doVisitBrOnCast(SubType* self, Expression** currp) {
-    self->visitBrOnCast((*currp)->cast<BrOnCast>());
-  }
-  static void doVisitRttCanon(SubType* self, Expression** currp) {
-    self->visitRttCanon((*currp)->cast<RttCanon>());
-  }
-  static void doVisitRttSub(SubType* self, Expression** currp) {
-    self->visitRttSub((*currp)->cast<RttSub>());
-  }
-  static void doVisitStructNew(SubType* self, Expression** currp) {
-    self->visitStructNew((*currp)->cast<StructNew>());
-  }
-  static void doVisitStructGet(SubType* self, Expression** currp) {
-    self->visitStructGet((*currp)->cast<StructGet>());
-  }
-  static void doVisitStructSet(SubType* self, Expression** currp) {
-    self->visitStructSet((*currp)->cast<StructSet>());
-  }
-  static void doVisitArrayNew(SubType* self, Expression** currp) {
-    self->visitArrayNew((*currp)->cast<ArrayNew>());
-  }
-  static void doVisitArrayGet(SubType* self, Expression** currp) {
-    self->visitArrayGet((*currp)->cast<ArrayGet>());
-  }
-  static void doVisitArraySet(SubType* self, Expression** currp) {
-    self->visitArraySet((*currp)->cast<ArraySet>());
-  }
-  static void doVisitArrayLen(SubType* self, Expression** currp) {
-    self->visitArrayLen((*currp)->cast<ArrayLen>());
-  }
-
-  void setModule(Module* module) { currModule = module; }
-
-  void setFunction(Function* func) { currFunction = func; }
-
-private:
-  // the address of the current node, used to replace it
-  Expression** replacep = nullptr;
-  SmallVector<Task, 10> stack;      // stack of tasks
-  Function* currFunction = nullptr; // current function being processed
-  Module* currModule = nullptr;     // current module being processed
-};
-
-// Walks in post-order, i.e., children first. When there isn't an obvious
-// order to operands, we follow them in order of execution.
-
-template<typename SubType, typename VisitorType = Visitor<SubType>>
-struct PostWalker : public Walker<SubType, VisitorType> {
-
-  static void scan(SubType* self, Expression** currp) {
-    Expression* curr = *currp;
-    switch (curr->_id) {
-      case Expression::Id::InvalidId:
-        abort();
-      case Expression::Id::BlockId: {
-        self->pushTask(SubType::doVisitBlock, currp);
-        auto& list = curr->cast<Block>()->list;
-        for (int i = int(list.size()) - 1; i >= 0; i--) {
-          self->pushTask(SubType::scan, &list[i]);
-        }
-        break;
-      }
-      case Expression::Id::IfId: {
-        self->pushTask(SubType::doVisitIf, currp);
-        self->maybePushTask(SubType::scan, &curr->cast<If>()->ifFalse);
-        self->pushTask(SubType::scan, &curr->cast<If>()->ifTrue);
-        self->pushTask(SubType::scan, &curr->cast<If>()->condition);
-        break;
-      }
-      case Expression::Id::LoopId: {
-        self->pushTask(SubType::doVisitLoop, currp);
-        self->pushTask(SubType::scan, &curr->cast<Loop>()->body);
-        break;
-      }
-      case Expression::Id::BreakId: {
-        self->pushTask(SubType::doVisitBreak, currp);
-        self->maybePushTask(SubType::scan, &curr->cast<Break>()->condition);
-        self->maybePushTask(SubType::scan, &curr->cast<Break>()->value);
-        break;
-      }
-      case Expression::Id::SwitchId: {
-        self->pushTask(SubType::doVisitSwitch, currp);
-        self->pushTask(SubType::scan, &curr->cast<Switch>()->condition);
-        self->maybePushTask(SubType::scan, &curr->cast<Switch>()->value);
-        break;
-      }
-      case Expression::Id::CallId: {
-        self->pushTask(SubType::doVisitCall, currp);
-        auto& list = curr->cast<Call>()->operands;
-        for (int i = int(list.size()) - 1; i >= 0; i--) {
-          self->pushTask(SubType::scan, &list[i]);
-        }
-        break;
-      }
-      case Expression::Id::CallIndirectId: {
-        self->pushTask(SubType::doVisitCallIndirect, currp);
-        auto& list = curr->cast<CallIndirect>()->operands;
-        self->pushTask(SubType::scan, &curr->cast<CallIndirect>()->target);
-        for (int i = int(list.size()) - 1; i >= 0; i--) {
-          self->pushTask(SubType::scan, &list[i]);
-        }
-        break;
-      }
-      case Expression::Id::LocalGetId: {
-        // TODO: optimize leaves with a direct call?
-        self->pushTask(SubType::doVisitLocalGet, currp);
-        break;
-      }
-      case Expression::Id::LocalSetId: {
-        self->pushTask(SubType::doVisitLocalSet, currp);
-        self->pushTask(SubType::scan, &curr->cast<LocalSet>()->value);
-        break;
-      }
-      case Expression::Id::GlobalGetId: {
-        self->pushTask(SubType::doVisitGlobalGet, currp);
-        break;
-      }
-      case Expression::Id::GlobalSetId: {
-        self->pushTask(SubType::doVisitGlobalSet, currp);
-        self->pushTask(SubType::scan, &curr->cast<GlobalSet>()->value);
-        break;
-      }
-      case Expression::Id::LoadId: {
-        self->pushTask(SubType::doVisitLoad, currp);
-        self->pushTask(SubType::scan, &curr->cast<Load>()->ptr);
-        break;
-      }
-      case Expression::Id::StoreId: {
-        self->pushTask(SubType::doVisitStore, currp);
-        self->pushTask(SubType::scan, &curr->cast<Store>()->value);
-        self->pushTask(SubType::scan, &curr->cast<Store>()->ptr);
-        break;
-      }
-      case Expression::Id::AtomicRMWId: {
-        self->pushTask(SubType::doVisitAtomicRMW, currp);
-        self->pushTask(SubType::scan, &curr->cast<AtomicRMW>()->value);
-        self->pushTask(SubType::scan, &curr->cast<AtomicRMW>()->ptr);
-        break;
-      }
-      case Expression::Id::AtomicCmpxchgId: {
-        self->pushTask(SubType::doVisitAtomicCmpxchg, currp);
-        self->pushTask(SubType::scan,
-                       &curr->cast<AtomicCmpxchg>()->replacement);
-        self->pushTask(SubType::scan, &curr->cast<AtomicCmpxchg>()->expected);
-        self->pushTask(SubType::scan, &curr->cast<AtomicCmpxchg>()->ptr);
-        break;
-      }
-      case Expression::Id::AtomicWaitId: {
-        self->pushTask(SubType::doVisitAtomicWait, currp);
-        self->pushTask(SubType::scan, &curr->cast<AtomicWait>()->timeout);
-        self->pushTask(SubType::scan, &curr->cast<AtomicWait>()->expected);
-        self->pushTask(SubType::scan, &curr->cast<AtomicWait>()->ptr);
-        break;
-      }
-      case Expression::Id::AtomicNotifyId: {
-        self->pushTask(SubType::doVisitAtomicNotify, currp);
-        self->pushTask(SubType::scan, &curr->cast<AtomicNotify>()->notifyCount);
-        self->pushTask(SubType::scan, &curr->cast<AtomicNotify>()->ptr);
-        break;
-      }
-      case Expression::Id::AtomicFenceId: {
-        self->pushTask(SubType::doVisitAtomicFence, currp);
-        break;
-      }
-      case Expression::Id::SIMDExtractId: {
-        self->pushTask(SubType::doVisitSIMDExtract, currp);
-        self->pushTask(SubType::scan, &curr->cast<SIMDExtract>()->vec);
-        break;
-      }
-      case Expression::Id::SIMDReplaceId: {
-        self->pushTask(SubType::doVisitSIMDReplace, currp);
-        self->pushTask(SubType::scan, &curr->cast<SIMDReplace>()->value);
-        self->pushTask(SubType::scan, &curr->cast<SIMDReplace>()->vec);
-        break;
-      }
-      case Expression::Id::SIMDShuffleId: {
-        self->pushTask(SubType::doVisitSIMDShuffle, currp);
-        self->pushTask(SubType::scan, &curr->cast<SIMDShuffle>()->right);
-        self->pushTask(SubType::scan, &curr->cast<SIMDShuffle>()->left);
-        break;
-      }
-      case Expression::Id::SIMDTernaryId: {
-        self->pushTask(SubType::doVisitSIMDTernary, currp);
-        self->pushTask(SubType::scan, &curr->cast<SIMDTernary>()->c);
-        self->pushTask(SubType::scan, &curr->cast<SIMDTernary>()->b);
-        self->pushTask(SubType::scan, &curr->cast<SIMDTernary>()->a);
-        break;
-      }
-      case Expression::Id::SIMDShiftId: {
-        self->pushTask(SubType::doVisitSIMDShift, currp);
-        self->pushTask(SubType::scan, &curr->cast<SIMDShift>()->shift);
-        self->pushTask(SubType::scan, &curr->cast<SIMDShift>()->vec);
-        break;
-      }
-      case Expression::Id::SIMDLoadId: {
-        self->pushTask(SubType::doVisitSIMDLoad, currp);
-        self->pushTask(SubType::scan, &curr->cast<SIMDLoad>()->ptr);
-        break;
-      }
-      case Expression::Id::MemoryInitId: {
-        self->pushTask(SubType::doVisitMemoryInit, currp);
-        self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->size);
-        self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->offset);
-        self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->dest);
-        break;
-      }
-      case Expression::Id::DataDropId: {
-        self->pushTask(SubType::doVisitDataDrop, currp);
-        break;
-      }
-      case Expression::Id::MemoryCopyId: {
-        self->pushTask(SubType::doVisitMemoryCopy, currp);
-        self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->size);
-        self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->source);
-        self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->dest);
-        break;
-      }
-      case Expression::Id::MemoryFillId: {
-        self->pushTask(SubType::doVisitMemoryFill, currp);
-        self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->size);
-        self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->value);
-        self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->dest);
-        break;
-      }
-      case Expression::Id::ConstId: {
-        self->pushTask(SubType::doVisitConst, currp);
-        break;
-      }
-      case Expression::Id::UnaryId: {
-        self->pushTask(SubType::doVisitUnary, currp);
-        self->pushTask(SubType::scan, &curr->cast<Unary>()->value);
-        break;
-      }
-      case Expression::Id::BinaryId: {
-        self->pushTask(SubType::doVisitBinary, currp);
-        self->pushTask(SubType::scan, &curr->cast<Binary>()->right);
-        self->pushTask(SubType::scan, &curr->cast<Binary>()->left);
-        break;
-      }
-      case Expression::Id::SelectId: {
-        self->pushTask(SubType::doVisitSelect, currp);
-        self->pushTask(SubType::scan, &curr->cast<Select>()->condition);
-        self->pushTask(SubType::scan, &curr->cast<Select>()->ifFalse);
-        self->pushTask(SubType::scan, &curr->cast<Select>()->ifTrue);
-        break;
-      }
-      case Expression::Id::DropId: {
-        self->pushTask(SubType::doVisitDrop, currp);
-        self->pushTask(SubType::scan, &curr->cast<Drop>()->value);
-        break;
-      }
-      case Expression::Id::ReturnId: {
-        self->pushTask(SubType::doVisitReturn, currp);
-        self->maybePushTask(SubType::scan, &curr->cast<Return>()->value);
-        break;
-      }
-      case Expression::Id::MemorySizeId:
-        self->pushTask(SubType::doVisitMemorySize, currp);
-        break;
-      case Expression::Id::MemoryGrowId:
-        self->pushTask(SubType::doVisitMemoryGrow, currp);
-        self->pushTask(SubType::scan, &curr->cast<MemoryGrow>()->delta);
-        break;
-      case Expression::Id::RefNullId: {
-        self->pushTask(SubType::doVisitRefNull, currp);
-        break;
-      }
-      case Expression::Id::RefIsNullId: {
-        self->pushTask(SubType::doVisitRefIsNull, currp);
-        self->pushTask(SubType::scan, &curr->cast<RefIsNull>()->value);
-        break;
-      }
-      case Expression::Id::RefFuncId: {
-        self->pushTask(SubType::doVisitRefFunc, currp);
-        break;
-      }
-      case Expression::Id::RefEqId: {
-        self->pushTask(SubType::doVisitRefEq, currp);
-        self->pushTask(SubType::scan, &curr->cast<RefEq>()->right);
-        self->pushTask(SubType::scan, &curr->cast<RefEq>()->left);
-        break;
-      }
-      case Expression::Id::TryId: {
-        self->pushTask(SubType::doVisitTry, currp);
-        self->pushTask(SubType::scan, &curr->cast<Try>()->catchBody);
-        self->pushTask(SubType::scan, &curr->cast<Try>()->body);
-        break;
-      }
-      case Expression::Id::ThrowId: {
-        self->pushTask(SubType::doVisitThrow, currp);
-        auto& list = curr->cast<Throw>()->operands;
-        for (int i = int(list.size()) - 1; i >= 0; i--) {
-          self->pushTask(SubType::scan, &list[i]);
-        }
-        break;
-      }
-      case Expression::Id::RethrowId: {
-        self->pushTask(SubType::doVisitRethrow, currp);
-        self->pushTask(SubType::scan, &curr->cast<Rethrow>()->exnref);
-        break;
-      }
-      case Expression::Id::BrOnExnId: {
-        self->pushTask(SubType::doVisitBrOnExn, currp);
-        self->pushTask(SubType::scan, &curr->cast<BrOnExn>()->exnref);
-        break;
-      }
-      case Expression::Id::NopId: {
-        self->pushTask(SubType::doVisitNop, currp);
-        break;
-      }
-      case Expression::Id::UnreachableId: {
-        self->pushTask(SubType::doVisitUnreachable, currp);
-        break;
-      }
-      case Expression::Id::PopId: {
-        self->pushTask(SubType::doVisitPop, currp);
-        break;
-      }
-      case Expression::Id::TupleMakeId: {
-        self->pushTask(SubType::doVisitTupleMake, currp);
-        auto& operands = curr->cast<TupleMake>()->operands;
-        for (int i = int(operands.size()) - 1; i >= 0; --i) {
-          self->pushTask(SubType::scan, &operands[i]);
-        }
-        break;
-      }
-      case Expression::Id::TupleExtractId: {
-        self->pushTask(SubType::doVisitTupleExtract, currp);
-        self->pushTask(SubType::scan, &curr->cast<TupleExtract>()->tuple);
-        break;
-      }
-      case Expression::Id::I31NewId: {
-        self->pushTask(SubType::doVisitI31New, currp);
-        self->pushTask(SubType::scan, &curr->cast<I31New>()->value);
-        break;
-      }
-      case Expression::Id::I31GetId: {
-        self->pushTask(SubType::doVisitI31Get, currp);
-        self->pushTask(SubType::scan, &curr->cast<I31Get>()->i31);
-        break;
-      }
-      case Expression::Id::RefTestId:
-        self->pushTask(SubType::doVisitRefTest, currp);
-        WASM_UNREACHABLE("TODO (gc): ref.test");
-        break;
-      case Expression::Id::RefCastId:
-        self->pushTask(SubType::doVisitRefCast, currp);
-        WASM_UNREACHABLE("TODO (gc): ref.cast");
-        break;
-      case Expression::Id::BrOnCastId:
-        self->pushTask(SubType::doVisitBrOnCast, currp);
-        WASM_UNREACHABLE("TODO (gc): br_on_cast");
-        break;
-      case Expression::Id::RttCanonId:
-        self->pushTask(SubType::doVisitRttCanon, currp);
-        WASM_UNREACHABLE("TODO (gc): rtt.canon");
-        break;
-      case Expression::Id::RttSubId:
-        self->pushTask(SubType::doVisitRttSub, currp);
-        WASM_UNREACHABLE("TODO (gc): rtt.sub");
-        break;
-      case Expression::Id::StructNewId:
-        self->pushTask(SubType::doVisitStructNew, currp);
-        WASM_UNREACHABLE("TODO (gc): struct.new");
-        break;
-      case Expression::Id::StructGetId:
-        self->pushTask(SubType::doVisitStructGet, currp);
-        WASM_UNREACHABLE("TODO (gc): struct.get");
-        break;
-      case Expression::Id::StructSetId:
-        self->pushTask(SubType::doVisitStructSet, currp);
-        WASM_UNREACHABLE("TODO (gc): struct.set");
-        break;
-      case Expression::Id::ArrayNewId:
-        self->pushTask(SubType::doVisitArrayNew, currp);
-        WASM_UNREACHABLE("TODO (gc): array.new");
-        break;
-      case Expression::Id::ArrayGetId:
-        self->pushTask(SubType::doVisitArrayGet, currp);
-        WASM_UNREACHABLE("TODO (gc): array.get");
-        break;
-      case Expression::Id::ArraySetId:
-        self->pushTask(SubType::doVisitArraySet, currp);
-        WASM_UNREACHABLE("TODO (gc): array.set");
-        break;
-      case Expression::Id::ArrayLenId:
-        self->pushTask(SubType::doVisitArrayLen, currp);
-        WASM_UNREACHABLE("TODO (gc): array.len");
-        break;
-      case Expression::Id::NumExpressionIds:
-        WASM_UNREACHABLE("unexpected expression type");
-    }
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  ReturnType visit##CLASS_TO_VISIT(CLASS_TO_VISIT* curr) {                     \
+    return ReturnType();                                                       \
+  }
+#include "wasm-delegations.h"
+
+  // Module-level visitors
+  ReturnType visitExport(Export* curr) { return ReturnType(); }
+  ReturnType visitGlobal(Global* curr) { return ReturnType(); }
+  ReturnType visitFunction(Function* curr) { return ReturnType(); }
+  ReturnType visitTable(Table* curr) { return ReturnType(); }
+  ReturnType visitMemory(Memory* curr) { return ReturnType(); }
+  ReturnType visitEvent(Event* curr) { return ReturnType(); }
+  ReturnType visitModule(Module* curr) { return ReturnType(); }
+
+  ReturnType visit(Expression* curr) {
+    assert(curr);
+
+    switch (curr->_id) {
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  case Expression::Id::CLASS_TO_VISIT##Id:                                     \
+    return static_cast<SubType*>(this)->visit##CLASS_TO_VISIT(                 \
+      static_cast<CLASS_TO_VISIT*>(curr))
+
+#include "wasm-delegations.h"
+
+      default:
+        WASM_UNREACHABLE("unexpected expression type");
+    }
+  }
+};
+
+// A visitor which must be overridden for each visitor that is reached.
+
+template<typename SubType, typename ReturnType = void>
+struct OverriddenVisitor {
+// Expression visitors, which must be overridden
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  ReturnType visit##CLASS_TO_VISIT(CLASS_TO_VISIT* curr) {                     \
+    static_assert(                                                             \
+      &SubType::visit##CLASS_TO_VISIT !=                                       \
+        &OverriddenVisitor<SubType, ReturnType>::visit##CLASS_TO_VISIT,        \
+      "Derived class must implement visit" #CLASS_TO_VISIT);                   \
+    WASM_UNREACHABLE("Derived class must implement visit" #CLASS_TO_VISIT);    \
+  }
+
+#include "wasm-delegations.h"
+
+  ReturnType visit(Expression* curr) {
+    assert(curr);
+
+    switch (curr->_id) {
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  case Expression::Id::CLASS_TO_VISIT##Id:                                     \
+    return static_cast<SubType*>(this)->visit##CLASS_TO_VISIT(                 \
+      static_cast<CLASS_TO_VISIT*>(curr))
+
+#include "wasm-delegations.h"
+
+      default:
+        WASM_UNREACHABLE("unexpected expression type");
+    }
+  }
+};
+
+// Visit with a single unified visitor, called on every node, instead of
+// separate visit* per node
+
+template<typename SubType, typename ReturnType = void>
+struct UnifiedExpressionVisitor : public Visitor<SubType, ReturnType> {
+  // called on each node
+  ReturnType visitExpression(Expression* curr) { return ReturnType(); }
+
+  // redirects
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  ReturnType visit##CLASS_TO_VISIT(CLASS_TO_VISIT* curr) {                     \
+    return static_cast<SubType*>(this)->visitExpression(curr);                 \
+  }
+
+#include "wasm-delegations.h"
+};
+
+//
+// Base class for all WasmWalkers, which can traverse an AST
+// and provide the option to replace nodes while doing so.
+//
+// Subclass and implement the visit*()
+// calls to run code on different node types.
+//
+template<typename SubType, typename VisitorType>
+struct Walker : public VisitorType {
+  // Useful methods for visitor implementions
+
+  // Replace the current node. You can call this in your visit*() methods.
+  // Note that the visit*() for the result node is not called for you (i.e.,
+  // just one visit*() method is called by the traversal; if you replace a node,
+  // and you want to process the output, you must do that explicitly).
+  Expression* replaceCurrent(Expression* expression) {
+    // Copy debug info, if present.
+    if (currFunction) {
+      auto& debugLocations = currFunction->debugLocations;
+      if (!debugLocations.empty()) {
+        auto* curr = getCurrent();
+        auto iter = debugLocations.find(curr);
+        if (iter != debugLocations.end()) {
+          auto location = iter->second;
+          debugLocations.erase(iter);
+          debugLocations[expression] = location;
+        }
+      }
+    }
+    return *replacep = expression;
+  }
+
+  Expression* getCurrent() { return *replacep; }
+
+  Expression** getCurrentPointer() { return replacep; }
+
+  // Get the current module
+  Module* getModule() { return currModule; }
+
+  // Get the current function
+  Function* getFunction() { return currFunction; }
+
+  // Walk starting
+
+  void walkGlobal(Global* global) {
+    walk(global->init);
+    static_cast<SubType*>(this)->visitGlobal(global);
+  }
+
+  void walkFunction(Function* func) {
+    setFunction(func);
+    static_cast<SubType*>(this)->doWalkFunction(func);
+    static_cast<SubType*>(this)->visitFunction(func);
+    setFunction(nullptr);
+  }
+
+  void walkEvent(Event* event) {
+    static_cast<SubType*>(this)->visitEvent(event);
+  }
+
+  void walkFunctionInModule(Function* func, Module* module) {
+    setModule(module);
+    setFunction(func);
+    static_cast<SubType*>(this)->doWalkFunction(func);
+    static_cast<SubType*>(this)->visitFunction(func);
+    setFunction(nullptr);
+    setModule(nullptr);
+  }
+
+  // override this to provide custom functionality
+  void doWalkFunction(Function* func) { walk(func->body); }
+
+  void walkTable(Table* table) {
+    for (auto& segment : table->segments) {
+      walk(segment.offset);
+    }
+    static_cast<SubType*>(this)->visitTable(table);
+  }
+
+  void walkMemory(Memory* memory) {
+    for (auto& segment : memory->segments) {
+      if (!segment.isPassive) {
+        walk(segment.offset);
+      }
+    }
+    static_cast<SubType*>(this)->visitMemory(memory);
+  }
+
+  void walkModule(Module* module) {
+    setModule(module);
+    static_cast<SubType*>(this)->doWalkModule(module);
+    static_cast<SubType*>(this)->visitModule(module);
+    setModule(nullptr);
+  }
+
+  // override this to provide custom functionality
+  void doWalkModule(Module* module) {
+    // Dispatch statically through the SubType.
+    SubType* self = static_cast<SubType*>(this);
+    for (auto& curr : module->exports) {
+      self->visitExport(curr.get());
+    }
+    for (auto& curr : module->globals) {
+      if (curr->imported()) {
+        self->visitGlobal(curr.get());
+      } else {
+        self->walkGlobal(curr.get());
+      }
+    }
+    for (auto& curr : module->functions) {
+      if (curr->imported()) {
+        self->visitFunction(curr.get());
+      } else {
+        self->walkFunction(curr.get());
+      }
+    }
+    for (auto& curr : module->events) {
+      if (curr->imported()) {
+        self->visitEvent(curr.get());
+      } else {
+        self->walkEvent(curr.get());
+      }
+    }
+    self->walkTable(&module->table);
+    self->walkMemory(&module->memory);
+  }
+
+  // Walk implementation. We don't use recursion as ASTs may be highly
+  // nested.
+
+  // Tasks receive the this pointer and a pointer to the pointer to operate on
+  typedef void (*TaskFunc)(SubType*, Expression**);
+
+  struct Task {
+    TaskFunc func;
+    Expression** currp;
+    Task() {}
+    Task(TaskFunc func, Expression** currp) : func(func), currp(currp) {}
+  };
+
+  void pushTask(TaskFunc func, Expression** currp) {
+    assert(*currp);
+    stack.emplace_back(func, currp);
+  }
+  void maybePushTask(TaskFunc func, Expression** currp) {
+    if (*currp) {
+      stack.emplace_back(func, currp);
+    }
+  }
+  Task popTask() {
+    auto ret = stack.back();
+    stack.pop_back();
+    return ret;
+  }
+
+  void walk(Expression*& root) {
+    assert(stack.size() == 0);
+    pushTask(SubType::scan, &root);
+    while (stack.size() > 0) {
+      auto task = popTask();
+      replacep = task.currp;
+      assert(*task.currp);
+      task.func(static_cast<SubType*>(this), task.currp);
+    }
+  }
+
+  // subclasses implement this to define the proper order of execution
+  static void scan(SubType* self, Expression** currp) { abort(); }
+
+  // task hooks to call visitors
+
+#define DELEGATE(CLASS_TO_VISIT)                                               \
+  static void doVisit##CLASS_TO_VISIT(SubType* self, Expression** currp) {     \
+    self->visit##CLASS_TO_VISIT((*currp)->cast<CLASS_TO_VISIT>());             \
+  }
+
+#include "wasm-delegations.h"
+
+  void setModule(Module* module) { currModule = module; }
+
+  void setFunction(Function* func) { currFunction = func; }
+
+private:
+  // the address of the current node, used to replace it
+  Expression** replacep = nullptr;
+  SmallVector<Task, 10> stack;      // stack of tasks
+  Function* currFunction = nullptr; // current function being processed
+  Module* currModule = nullptr;     // current module being processed
+};
+
+// Walks in post-order, i.e., children first. When there isn't an obvious
+// order to operands, we follow them in order of execution.
+
+template<typename SubType, typename VisitorType = Visitor<SubType>>
+struct PostWalker : public Walker<SubType, VisitorType> {
+
+  static void scan(SubType* self, Expression** currp) {
+    Expression* curr = *currp;
+
+#define DELEGATE_ID curr->_id
+
+#define DELEGATE_START(id)                                                     \
+  self->pushTask(SubType::doVisit##id, currp);                                 \
+  auto* cast = curr->cast<id>();                                               \
+  WASM_UNUSED(cast);
+
+#define DELEGATE_GET_FIELD(id, name) cast->name
+
+#define DELEGATE_FIELD_CHILD(id, name)                                         \
+  self->pushTask(SubType::scan, &cast->name);
+
+#define DELEGATE_FIELD_OPTIONAL_CHILD(id, name)                                \
+  self->maybePushTask(SubType::scan, &cast->name);
+
+#define DELEGATE_FIELD_INT(id, name)
+#define DELEGATE_FIELD_INT_ARRAY(id, name)
+#define DELEGATE_FIELD_LITERAL(id, name)
+#define DELEGATE_FIELD_NAME(id, name)
+#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, name)
+#define DELEGATE_FIELD_SCOPE_NAME_USE(id, name)
+#define DELEGATE_FIELD_SCOPE_NAME_USE_VECTOR(id, name)
+#define DELEGATE_FIELD_SIGNATURE(id, name)
+#define DELEGATE_FIELD_TYPE(id, name)
+#define DELEGATE_FIELD_ADDRESS(id, name)
+
+#include "wasm-delegations-fields.h"
   }
 };
 
diff --git a/binaryen/src/wasm-type.h b/binaryen/src/wasm-type.h
--- a/binaryen/src/wasm-type.h
+++ b/binaryen/src/wasm-type.h
@@ -17,6 +17,7 @@
 #ifndef wasm_wasm_type_h
 #define wasm_wasm_type_h
 
+#include "support/name.h"
 #include "wasm-features.h"
 #include <ostream>
 #include <vector>
@@ -31,15 +32,37 @@
 
 namespace wasm {
 
+// The types defined in this file. All of them are small and typically passed by
+// value except for `Tuple` and `Struct`, which may own an unbounded amount of
+// data.
+class Type;
+class HeapType;
+struct Tuple;
+struct Signature;
+struct Field;
+struct Struct;
+struct Array;
+struct Rtt;
+
+enum Nullability { NonNullable, Nullable };
+enum Mutability { Immutable, Mutable };
+
+// The type used for interning IDs in the public interfaces of Type and
+// HeapType.
+using TypeID = uint64_t;
+
 class Type {
   // The `id` uniquely represents each type, so type equality is just a
-  // comparison of the ids. For basic types the `id` is just the `BasicID`
+  // comparison of the ids. For basic types the `id` is just the `BasicType`
   // enum value below, and for constructed types the `id` is the address of the
   // canonical representation of the type, making lookups cheap for all types.
+  // Since `Type` is really just a single integer, it should be passed by value.
+  // This is a uintptr_t rather than a TypeID (uint64_t) to save memory on
+  // 32-bit platforms.
   uintptr_t id;
 
 public:
-  enum BasicID : uint32_t {
+  enum BasicType : uint32_t {
     none,
     unreachable,
     i32,
@@ -53,29 +76,30 @@
     anyref,
     eqref,
     i31ref,
-    _last_basic_id = i31ref,
   };
+  static constexpr BasicType _last_basic_type = i31ref;
 
-  Type() = default;
+  Type() : id(none) {}
 
-  // BasicID can be implicitly upgraded to Type
-  constexpr Type(BasicID id) : id(id){};
+  // BasicType can be implicitly upgraded to Type
+  constexpr Type(BasicType id) : id(id) {}
 
-  // But converting raw uint32_t is more dangerous, so make it explicit
-  explicit Type(uint64_t id) : id(id){};
+  // But converting raw TypeID is more dangerous, so make it explicit
+  explicit Type(TypeID id) : id(id) {}
 
   // Construct tuple from a list of single types
   Type(std::initializer_list<Type>);
 
   // Construct from tuple description
-  explicit Type(const struct Tuple&);
+  Type(const Tuple&);
+  Type(Tuple&&);
 
   // Construct from a heap type description. Also covers construction from
   // Signature, Struct or Array via implicit conversion to HeapType.
-  explicit Type(const struct HeapType&, bool nullable);
+  Type(HeapType, Nullability nullable);
 
   // Construct from rtt description
-  explicit Type(const struct Rtt&);
+  Type(Rtt);
 
   // Predicates
   //                 Compound Concrete
@@ -101,8 +125,8 @@
   // │ Tuple       ║   │ x │   │ x │       │
   // │ Rtt         ║   │ x │ x │ x │       │
   // └─────────────╨───┴───┴───┴───┴───────┘
-  constexpr bool isBasic() const { return id <= _last_basic_id; }
-  constexpr bool isCompound() const { return id > _last_basic_id; }
+  constexpr bool isBasic() const { return id <= _last_basic_type; }
+  constexpr bool isCompound() const { return id > _last_basic_type; }
   constexpr bool isConcrete() const { return id >= i32; }
   constexpr bool isInteger() const { return id == i32 || id == i64; }
   constexpr bool isFloat() const { return id == f32 || id == f64; }
@@ -115,6 +139,8 @@
   bool isException() const;
   bool isNullable() const;
   bool isRtt() const;
+  bool isStruct() const;
+  bool isArray() const;
 
 private:
   template<bool (Type::*pred)() const> bool hasPredicate() {
@@ -130,19 +156,19 @@
   bool hasVector() { return hasPredicate<&Type::isVector>(); }
   bool hasRef() { return hasPredicate<&Type::isRef>(); }
 
-  constexpr uint64_t getID() const { return id; }
-  constexpr BasicID getBasic() const {
+  constexpr TypeID getID() const { return id; }
+  constexpr BasicType getBasic() const {
     assert(isBasic() && "Basic type expected");
-    return static_cast<BasicID>(id);
+    return static_cast<BasicType>(id);
   }
 
-  // (In)equality must be defined for both Type and BasicID because it is
+  // (In)equality must be defined for both Type and BasicType because it is
   // otherwise ambiguous whether to convert both this and other to int or
   // convert other to Type.
   bool operator==(const Type& other) const { return id == other.id; }
-  bool operator==(const BasicID& otherId) const { return id == otherId; }
+  bool operator==(const BasicType& other) const { return id == other; }
   bool operator!=(const Type& other) const { return id != other.id; }
-  bool operator!=(const BasicID& otherId) const { return id != otherId; }
+  bool operator!=(const BasicType& other) const { return id != other; }
 
   // Order types by some notion of simplicity
   bool operator<(const Type& other) const;
@@ -157,9 +183,13 @@
   // Returns the feature set required to use this type.
   FeatureSet getFeatures() const;
 
-  // Gets the heap type corresponding to this type
+  // Gets the heap type corresponding to this type, assuming that it is a
+  // reference or Rtt type.
   HeapType getHeapType() const;
 
+  // Gets the Rtt for this type, assuming that it is an Rtt type.
+  Rtt getRtt() const;
+
   // Returns a number type based on its size in bytes and whether it is a float
   // type.
   static Type get(unsigned byteSize, bool float_);
@@ -251,17 +281,90 @@
   std::string toString() const;
 };
 
+class HeapType {
+  // Unlike `Type`, which represents the types of values on the WebAssembly
+  // stack, `HeapType` is used to describe the structures that reference types
+  // refer to. HeapTypes are canonicalized and interned exactly like Types and
+  // should also be passed by value.
+  uintptr_t id;
+
+public:
+  enum BasicHeapType : uint32_t {
+    func,
+    ext,
+    exn,
+    any,
+    eq,
+    i31,
+  };
+  static constexpr BasicHeapType _last_basic_type = i31;
+
+  // BasicHeapType can be implicitly upgraded to HeapType
+  constexpr HeapType(BasicHeapType id) : id(id) {}
+
+  // But converting raw TypeID is more dangerous, so make it explicit
+  explicit HeapType(TypeID id) : id(id) {}
+
+  HeapType(Signature signature);
+  HeapType(const Struct& struct_);
+  HeapType(Struct&& struct_);
+  HeapType(Array array);
+
+  constexpr bool isBasic() const { return id <= _last_basic_type; }
+  constexpr bool isCompound() const { return id > _last_basic_type; }
+  bool isFunction() const;
+  bool isSignature() const;
+  bool isStruct() const;
+  bool isArray() const;
+
+  Signature getSignature() const;
+  const Struct& getStruct() const;
+  Array getArray() const;
+
+  constexpr TypeID getID() const { return id; }
+  constexpr BasicHeapType getBasic() const {
+    assert(isBasic() && "Basic heap type expected");
+    return static_cast<BasicHeapType>(id);
+  }
+
+  // (In)equality must be defined for both HeapType and BasicHeapType because it
+  // is otherwise ambiguous whether to convert both this and other to int or
+  // convert other to HeapType.
+  bool operator==(const HeapType& other) const { return id == other.id; }
+  bool operator==(const BasicHeapType& other) const { return id == other; }
+  bool operator!=(const HeapType& other) const { return id != other.id; }
+  bool operator!=(const BasicHeapType& other) const { return id != other; }
+
+  bool operator<(const HeapType& other) const;
+  std::string toString() const;
+};
+
 typedef std::vector<Type> TypeList;
 
+// Passed by reference rather than by value because it can own an unbounded
+// amount of data.
 struct Tuple {
   TypeList types;
   Tuple() : types() {}
-  Tuple(std::initializer_list<Type> types) : types(types) {}
-  Tuple(const TypeList& types) : types(types) {}
-  Tuple(TypeList&& types) : types(std::move(types)) {}
+  Tuple(std::initializer_list<Type> types) : types(types) { validate(); }
+  Tuple(const TypeList& types) : types(types) { validate(); }
+  Tuple(TypeList&& types) : types(std::move(types)) { validate(); }
   bool operator==(const Tuple& other) const { return types == other.types; }
   bool operator!=(const Tuple& other) const { return !(*this == other); }
+  bool operator<(const Tuple& other) const { return types < other.types; }
   std::string toString() const;
+
+  // Prevent accidental copies
+  Tuple& operator=(const Tuple&) = delete;
+
+private:
+  void validate() {
+#ifndef NDEBUG
+    for (auto type : types) {
+      assert(type.isSingle());
+    }
+#endif
+  }
 };
 
 struct Signature {
@@ -284,12 +387,13 @@
     i8,
     i16,
   } packedType; // applicable iff type=i32
-  bool mutable_;
+  Mutability mutable_;
+  Name name;
 
-  Field(Type type, bool mutable_ = false)
-    : type(type), packedType(not_packed), mutable_(mutable_) {}
-  Field(PackedType packedType, bool mutable_ = false)
-    : type(Type::i32), packedType(packedType), mutable_(mutable_) {}
+  Field(Type type, Mutability mutable_, Name name = Name())
+    : type(type), packedType(not_packed), mutable_(mutable_), name(name) {}
+  Field(PackedType packedType, Mutability mutable_, Name name = Name())
+    : type(Type::i32), packedType(packedType), mutable_(mutable_), name(name) {}
 
   constexpr bool isPacked() const {
     if (packedType != not_packed) {
@@ -300,15 +404,20 @@
   }
 
   bool operator==(const Field& other) const {
+    // Note that the name is not checked here - it is pure metadata for printing
+    // purposes only.
     return type == other.type && packedType == other.packedType &&
            mutable_ == other.mutable_;
   }
   bool operator!=(const Field& other) const { return !(*this == other); }
+  bool operator<(const Field& other) const;
   std::string toString() const;
 };
 
 typedef std::vector<Field> FieldList;
 
+// Passed by reference rather than by value because it can own an unbounded
+// amount of data.
 struct Struct {
   FieldList fields;
   Struct(const Struct& other) : fields(other.fields) {}
@@ -316,84 +425,73 @@
   Struct(FieldList&& fields) : fields(std::move(fields)) {}
   bool operator==(const Struct& other) const { return fields == other.fields; }
   bool operator!=(const Struct& other) const { return !(*this == other); }
+  bool operator<(const Struct& other) const { return fields < other.fields; }
   std::string toString() const;
+
+  // Prevent accidental copies
+  Struct& operator=(const Struct&) = delete;
 };
 
 struct Array {
   Field element;
   Array(const Array& other) : element(other.element) {}
-  Array(const Field& element) : element(element) {}
-  Array(Field&& element) : element(std::move(element)) {}
+  Array(Field element) : element(element) {}
   bool operator==(const Array& other) const { return element == other.element; }
   bool operator!=(const Array& other) const { return !(*this == other); }
-  std::string toString() const;
-};
-
-struct HeapType {
-  enum Kind {
-    FuncKind,
-    ExternKind,
-    ExnKind,
-    AnyKind,
-    EqKind,
-    I31Kind,
-    _last_basic_kind = I31Kind,
-    SignatureKind,
-    StructKind,
-    ArrayKind,
-  } kind;
-  union {
-    Signature signature;
-    Struct struct_;
-    Array array;
-  };
-  HeapType(Kind kind) : kind(kind) { assert(kind <= _last_basic_kind); }
-  HeapType(const Signature& signature)
-    : kind(SignatureKind), signature(signature) {}
-  HeapType(Signature&& signature)
-    : kind(SignatureKind), signature(std::move(signature)) {}
-  HeapType(const Struct& struct_) : kind(StructKind), struct_(struct_) {}
-  HeapType(Struct&& struct_) : kind(StructKind), struct_(std::move(struct_)) {}
-  HeapType(const Array& array) : kind(ArrayKind), array(array) {}
-  HeapType(Array&& array) : kind(ArrayKind), array(std::move(array)) {}
-  HeapType(const HeapType& other);
-  ~HeapType();
-
-  bool isSignature() const { return kind == SignatureKind; }
-  Signature getSignature() const {
-    assert(isSignature() && "Not a signature");
-    return signature;
-  }
-  bool isStruct() const { return kind == StructKind; }
-  Struct getStruct() const {
-    assert(isStruct() && "Not a struct");
-    return struct_;
-  }
-  bool isArray() const { return kind == ArrayKind; }
-  Array getArray() const {
-    assert(isArray() && "Not an array");
-    return array;
-  }
-  bool isException() const { return kind == ExnKind; }
-
-  bool operator==(const HeapType& other) const;
-  bool operator!=(const HeapType& other) const { return !(*this == other); }
-  HeapType& operator=(const HeapType& other);
+  bool operator<(const Array& other) const { return element < other.element; }
   std::string toString() const;
 };
 
 struct Rtt {
+  // An Rtt can have no depth specified
+  static constexpr uint32_t NoDepth = -1;
   uint32_t depth;
   HeapType heapType;
-  Rtt(uint32_t depth, const HeapType& heapType)
-    : depth(depth), heapType(heapType) {}
-  Rtt(uint32_t depth, HeapType&& heapType)
-    : depth(depth), heapType(std::move(heapType)) {}
+  Rtt(HeapType heapType) : depth(NoDepth), heapType(heapType) {}
+  Rtt(uint32_t depth, HeapType heapType) : depth(depth), heapType(heapType) {}
   bool operator==(const Rtt& other) const {
     return depth == other.depth && heapType == other.heapType;
   }
   bool operator!=(const Rtt& other) const { return !(*this == other); }
+  bool operator<(const Rtt& other) const;
+  bool hasDepth() { return depth != uint32_t(NoDepth); }
   std::string toString() const;
+};
+
+// TypeBuilder - allows for the construction of recursive types. Contains a
+// table of `n` mutable HeapTypes and can construct temporary types that are
+// backed by those HeapTypes, refering to them by reference. Those temporary
+// types are owned by the TypeBuilder and should only be used in the
+// construction of HeapTypes to insert into the TypeBuilder. Temporary types
+// should never be used in the construction of normal Types, only other
+// temporary types.
+struct TypeBuilder {
+  struct Impl;
+  std::unique_ptr<Impl> impl;
+
+  TypeBuilder(size_t n);
+  ~TypeBuilder();
+
+  TypeBuilder(TypeBuilder& other) = delete;
+  TypeBuilder(TypeBuilder&& other) = delete;
+  TypeBuilder& operator=(TypeBuilder&) = delete;
+
+  // Sets the heap type at index `i`. May only be called before `build`.
+  void setHeapType(size_t i, Signature signature);
+  void setHeapType(size_t i, const Struct& struct_);
+  void setHeapType(size_t i, Struct&& struct_);
+  void setHeapType(size_t i, Array array);
+
+  // Gets a temporary type or heap type for use in initializing the
+  // TypeBuilder's HeapTypes. Temporary Ref and Rtt types are backed by the
+  // HeapType at index `i`.
+  Type getTempTupleType(const Tuple&);
+  Type getTempRefType(size_t i, Nullability nullable);
+  Type getTempRttType(size_t i, uint32_t depth);
+
+  // Canonicalizes and returns all of the heap types. May only be called once
+  // all of the heap types have been initialized with `setHeapType`.
+  std::vector<HeapType> build();
 };
 
 std::ostream& operator<<(std::ostream&, Type);
diff --git a/binaryen/src/wasm-validator.h b/binaryen/src/wasm-validator.h
--- a/binaryen/src/wasm-validator.h
+++ b/binaryen/src/wasm-validator.h
@@ -43,7 +43,6 @@
 #include <sstream>
 #include <unordered_set>
 
-#include "wasm-printing.h"
 #include "wasm.h"
 
 namespace wasm {
diff --git a/binaryen/src/wasm.h b/binaryen/src/wasm.h
--- a/binaryen/src/wasm.h
+++ b/binaryen/src/wasm.h
@@ -28,6 +28,7 @@
 #include <array>
 #include <cassert>
 #include <map>
+#include <ostream>
 #include <string>
 #include <vector>
 
@@ -161,6 +162,7 @@
   AnyTrueVecI8x16,
   AllTrueVecI8x16,
   BitmaskVecI8x16,
+  PopcntVecI8x16,
   AbsVecI16x8,
   NegVecI16x8,
   AnyTrueVecI16x8,
@@ -172,8 +174,7 @@
   AllTrueVecI32x4,
   BitmaskVecI32x4,
   NegVecI64x2,
-  AnyTrueVecI64x2,
-  AllTrueVecI64x2,
+  BitmaskVecI64x2,
   AbsVecF32x4,
   NegVecF32x4,
   SqrtVecF32x4,
@@ -188,6 +189,10 @@
   FloorVecF64x2,
   TruncVecF64x2,
   NearestVecF64x2,
+  ExtAddPairwiseSVecI8x16ToI16x8,
+  ExtAddPairwiseUVecI8x16ToI16x8,
+  ExtAddPairwiseSVecI16x8ToI32x4,
+  ExtAddPairwiseUVecI16x8ToI32x4,
 
   // SIMD conversions
   TruncSatSVecF32x4ToVecI32x4,
@@ -206,6 +211,10 @@
   WidenHighSVecI16x8ToVecI32x4,
   WidenLowUVecI16x8ToVecI32x4,
   WidenHighUVecI16x8ToVecI32x4,
+  WidenLowSVecI32x4ToVecI64x2,
+  WidenHighSVecI32x4ToVecI64x2,
+  WidenLowUVecI32x4ToVecI64x2,
+  WidenHighUVecI32x4ToVecI64x2,
 
   InvalidUnary
 };
@@ -350,6 +359,7 @@
   LeUVecI32x4,
   GeSVecI32x4,
   GeUVecI32x4,
+  EqVecI64x2,
   EqVecF32x4,
   NeVecF32x4,
   LtVecF32x4,
@@ -392,6 +402,11 @@
   MaxSVecI16x8,
   MaxUVecI16x8,
   AvgrUVecI16x8,
+  Q15MulrSatSVecI16x8,
+  ExtMulLowSVecI16x8,
+  ExtMulHighSVecI16x8,
+  ExtMulLowUVecI16x8,
+  ExtMulHighUVecI16x8,
   AddVecI32x4,
   SubVecI32x4,
   MulVecI32x4,
@@ -400,9 +415,17 @@
   MaxSVecI32x4,
   MaxUVecI32x4,
   DotSVecI16x8ToVecI32x4,
+  ExtMulLowSVecI32x4,
+  ExtMulHighSVecI32x4,
+  ExtMulLowUVecI32x4,
+  ExtMulHighUVecI32x4,
   AddVecI64x2,
   SubVecI64x2,
   MulVecI64x2,
+  ExtMulLowSVecI64x2,
+  ExtMulHighSVecI64x2,
+  ExtMulLowUVecI64x2,
+  ExtMulHighUVecI64x2,
   AddVecF32x4,
   SubVecF32x4,
   MulVecF32x4,
@@ -432,7 +455,7 @@
   InvalidBinary
 };
 
-enum AtomicRMWOp { Add, Sub, And, Or, Xor, Xchg };
+enum AtomicRMWOp { RMWAdd, RMWSub, RMWAnd, RMWOr, RMWXor, RMWXchg };
 
 enum SIMDExtractOp {
   ExtractLaneSVecI8x16,
@@ -481,11 +504,37 @@
   LoadExtSVec32x2ToVecI64x2,
   LoadExtUVec32x2ToVecI64x2,
   Load32Zero,
-  Load64Zero
+  Load64Zero,
 };
 
-enum SIMDTernaryOp { Bitselect, QFMAF32x4, QFMSF32x4, QFMAF64x2, QFMSF64x2 };
+enum SIMDLoadStoreLaneOp {
+  LoadLaneVec8x16,
+  LoadLaneVec16x8,
+  LoadLaneVec32x4,
+  LoadLaneVec64x2,
+  StoreLaneVec8x16,
+  StoreLaneVec16x8,
+  StoreLaneVec32x4,
+  StoreLaneVec64x2,
+};
 
+enum SIMDTernaryOp {
+  Bitselect,
+  QFMAF32x4,
+  QFMSF32x4,
+  QFMAF64x2,
+  QFMSF64x2,
+  SignSelectVec8x16,
+  SignSelectVec16x8,
+  SignSelectVec32x4,
+  SignSelectVec64x2
+};
+
+enum PrefetchOp {
+  PrefetchTemporal,
+  PrefetchNontemporal,
+};
+
 //
 // Expressions
 //
@@ -533,6 +582,7 @@
     MemorySizeId,
     MemoryGrowId,
     NopId,
+    PrefetchId,
     UnreachableId,
     AtomicRMWId,
     AtomicCmpxchgId,
@@ -545,6 +595,7 @@
     SIMDTernaryId,
     SIMDShiftId,
     SIMDLoadId,
+    SIMDLoadStoreLaneId,
     MemoryInitId,
     DataDropId,
     MemoryCopyId,
@@ -562,6 +613,7 @@
     TupleExtractId,
     I31NewId,
     I31GetId,
+    CallRefId,
     RefTestId,
     RefCastId,
     BrOnCastId,
@@ -660,11 +712,13 @@
   // needed (which may require scanning the block)
   void finalize(Type type_);
 
+  enum Breakability { Unknown, HasBreak, NoBreak };
+
   // set the type given you know its type, and you know if there is a break to
   // this block. this avoids the need to scan the contents of the block in the
   // case that it might be unreachable, so it is recommended if you already know
   // the type and breakability anyhow.
-  void finalize(Type type_, bool hasBreak);
+  void finalize(Type type_, Breakability breakability);
 };
 
 class If : public SpecificExpression<Expression::IfId> {
@@ -970,6 +1024,37 @@
   void finalize();
 };
 
+class SIMDLoadStoreLane
+  : public SpecificExpression<Expression::SIMDLoadStoreLaneId> {
+public:
+  SIMDLoadStoreLane() = default;
+  SIMDLoadStoreLane(MixedArena& allocator) {}
+
+  SIMDLoadStoreLaneOp op;
+  Address offset;
+  Address align;
+  uint8_t index;
+  Expression* ptr;
+  Expression* vec;
+
+  bool isStore();
+  bool isLoad() { return !isStore(); }
+  Index getMemBytes();
+  void finalize();
+};
+
+class Prefetch : public SpecificExpression<Expression::PrefetchId> {
+public:
+  Prefetch() = default;
+  Prefetch(MixedArena& allocator) : Prefetch() {}
+
+  PrefetchOp op;
+  Address offset;
+  Address align;
+  Expression* ptr;
+  void finalize();
+};
+
 class MemoryInit : public SpecificExpression<Expression::MemoryInitId> {
 public:
   MemoryInit() = default;
@@ -1153,6 +1238,7 @@
   Name func;
 
   void finalize();
+  void finalize(Type type_);
 };
 
 class RefEq : public SpecificExpression<Expression::RefEqId> {
@@ -1248,97 +1334,181 @@
   void finalize();
 };
 
+class CallRef : public SpecificExpression<Expression::CallRefId> {
+public:
+  CallRef(MixedArena& allocator) : operands(allocator) {}
+  ExpressionList operands;
+  Expression* target;
+  bool isReturn = false;
+
+  void finalize();
+  void finalize(Type type_);
+};
+
 class RefTest : public SpecificExpression<Expression::RefTestId> {
 public:
   RefTest(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): ref.test"); }
+  Expression* ref;
+  Expression* rtt;
+
+  void finalize();
+
+  Type getCastType();
 };
 
 class RefCast : public SpecificExpression<Expression::RefCastId> {
 public:
   RefCast(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): ref.cast"); }
+  Expression* ref;
+  Expression* rtt;
+
+  void finalize();
+
+  Type getCastType();
 };
 
 class BrOnCast : public SpecificExpression<Expression::BrOnCastId> {
 public:
   BrOnCast(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): br_on_cast"); }
+  Name name;
+  // The cast type cannot be inferred from rtt if rtt is unreachable, so we must
+  // store it explicitly.
+  Type castType;
+  Expression* ref;
+  Expression* rtt;
+
+  void finalize();
+
+  Type getCastType();
 };
 
 class RttCanon : public SpecificExpression<Expression::RttCanonId> {
 public:
   RttCanon(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): rtt.canon"); }
+  void finalize();
 };
 
 class RttSub : public SpecificExpression<Expression::RttSubId> {
 public:
   RttSub(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): rtt.sub"); }
+  Expression* parent;
+
+  void finalize();
 };
 
 class StructNew : public SpecificExpression<Expression::StructNewId> {
 public:
-  StructNew(MixedArena& allocator) {}
+  StructNew(MixedArena& allocator) : operands(allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): struct.new"); }
+  Expression* rtt;
+  // A struct.new_with_default has empty operands. This does leave the case of a
+  // struct with no fields ambiguous, but it doesn't make a difference in that
+  // case, and binaryen doesn't guarantee roundtripping binaries anyhow.
+  ExpressionList operands;
+
+  bool isWithDefault() { return operands.empty(); }
+
+  void finalize();
 };
 
 class StructGet : public SpecificExpression<Expression::StructGetId> {
 public:
   StructGet(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): struct.get"); }
+  Index index;
+  Expression* ref;
+  // Packed fields have a sign.
+  bool signed_ = false;
+
+  void finalize();
 };
 
 class StructSet : public SpecificExpression<Expression::StructSetId> {
 public:
   StructSet(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): struct.set"); }
+  Index index;
+  Expression* ref;
+  Expression* value;
+
+  void finalize();
 };
 
 class ArrayNew : public SpecificExpression<Expression::ArrayNewId> {
 public:
   ArrayNew(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): array.new"); }
+  Expression* rtt;
+  Expression* size;
+  // If set, then the initial value is assigned to all entries in the array. If
+  // not set, this is array.new_with_default and the default of the type is
+  // used.
+  Expression* init = nullptr;
+
+  bool isWithDefault() { return !init; }
+
+  void finalize();
 };
 
 class ArrayGet : public SpecificExpression<Expression::ArrayGetId> {
 public:
   ArrayGet(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): array.get"); }
+  Expression* ref;
+  Expression* index;
+  // Packed fields have a sign.
+  bool signed_ = false;
+
+  void finalize();
 };
 
 class ArraySet : public SpecificExpression<Expression::ArraySetId> {
 public:
   ArraySet(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): array.set"); }
+  Expression* ref;
+  Expression* index;
+  Expression* value;
+
+  void finalize();
 };
 
 class ArrayLen : public SpecificExpression<Expression::ArrayLenId> {
 public:
   ArrayLen(MixedArena& allocator) {}
 
-  void finalize() { WASM_UNREACHABLE("TODO (gc): array.len"); }
+  Expression* ref;
+
+  void finalize();
 };
 
 // Globals
 
 struct Importable {
+  Name name;
+
+  // Explicit names are ones that we read from the input file and
+  // will be written the name section in the output file.
+  // Implicit names are names that binaryen generated for internal
+  // use only and will not be written the name section.
+  bool hasExplicitName = false;
+
   // If these are set, then this is an import, as module.base
   Name module, base;
 
-  bool imported() { return module.is(); }
+  bool imported() const { return module.is(); }
+
+  void setName(Name name_, bool hasExplicitName_) {
+    name = name_;
+    hasExplicitName = hasExplicitName_;
+  }
+
+  void setExplicitName(Name name_) { setName(name_, true); }
 };
 
 class Function;
@@ -1366,10 +1536,10 @@
   // control flow, have, like 'end' for loop and block. We keep these in a
   // separate map because they are rare and we optimize for the storage space
   // for the common type of instruction which just needs a Span. We implement
-  // this as a simple struct with two elements (as two extra elements is the
-  // maximum currently needed; due to 'catch' and 'end' for try-catch). The
-  // second value may be 0, indicating it is not used.
-  struct DelimiterLocations : public std::array<BinaryLocation, 2> {
+  // this as a simple array with one element at the moment (more elements may
+  // be necessary in the future).
+  // TODO: If we are sure we won't need more, make this a single value?
+  struct DelimiterLocations : public std::array<BinaryLocation, 1> {
     DelimiterLocations() {
       // Ensure zero-initialization.
       for (auto& item : *this) {
@@ -1378,14 +1548,7 @@
     }
   };
 
-  enum DelimiterId {
-    // All control flow structures have an end, so use index 0 for that.
-    End = 0,
-    // Use index 1 for all other current things.
-    Else = 1,
-    Catch = 1,
-    Invalid = -1
-  };
+  enum DelimiterId { Else = 0, Catch = 0, Invalid = -1 };
   std::unordered_map<Expression*, DelimiterLocations> delimiters;
 
   // DWARF debug info can refer to multiple interesting positions in a function.
@@ -1411,7 +1574,6 @@
 
 class Function : public Importable {
 public:
-  Name name;
   Signature sig; // parameters and return value
   IRProfile profile = IRProfile::Normal;
   std::vector<Type> vars; // non-param locals
@@ -1523,7 +1685,6 @@
   // been defined or imported. The table can exist but be empty and have no
   // defined initial or max size.
   bool exists = false;
-  Name name;
   Address initial = 0;
   Address max = kMaxSize;
   std::vector<Segment> segments;
@@ -1548,6 +1709,8 @@
     (uint64_t(4) * 1024 * 1024 * 1024) / kPageSize;
 
   struct Segment {
+    // For use in name section only
+    Name name;
     bool isPassive = false;
     Expression* offset = nullptr;
     std::vector<char> data; // TODO: optimize
@@ -1561,15 +1724,18 @@
     Segment(Expression* offset, std::vector<char>& init) : offset(offset) {
       data.swap(init);
     }
-    Segment(bool isPassive, Expression* offset, const char* init, Address size)
-      : isPassive(isPassive), offset(offset) {
+    Segment(Name name,
+            bool isPassive,
+            Expression* offset,
+            const char* init,
+            Address size)
+      : name(name), isPassive(isPassive), offset(offset) {
       data.resize(size);
       std::copy_n(init, size, data.begin());
     }
   };
 
   bool exists = false;
-  Name name;
   Address initial = 0; // sizes are in pages
   Address max = kMaxSize32;
   std::vector<Segment> segments;
@@ -1594,7 +1760,6 @@
 
 class Global : public Importable {
 public:
-  Name name;
   Type type;
   Expression* init = nullptr;
   bool mutable_ = false;
@@ -1605,7 +1770,6 @@
 
 class Event : public Importable {
 public:
-  Name name;
   // Kind of event. Currently only WASM_EVENT_ATTRIBUTE_EXCEPTION is possible.
   uint32_t attribute = WASM_EVENT_ATTRIBUTE_EXCEPTION;
   Signature sig;
@@ -1686,10 +1850,10 @@
   Global* addGlobal(Global* curr);
   Event* addEvent(Event* curr);
 
-  Export* addExport(std::unique_ptr<Export> curr);
-  Function* addFunction(std::unique_ptr<Function> curr);
-  Global* addGlobal(std::unique_ptr<Global> curr);
-  Event* addEvent(std::unique_ptr<Event> curr);
+  Export* addExport(std::unique_ptr<Export>&& curr);
+  Function* addFunction(std::unique_ptr<Function>&& curr);
+  Global* addGlobal(std::unique_ptr<Global>&& curr);
+  Event* addEvent(std::unique_ptr<Event>&& curr);
 
   void addStart(const Name& s);
 
@@ -1716,6 +1880,12 @@
     return std::hash<wasm::Address::address64_t>()(a.addr);
   }
 };
+
+std::ostream& operator<<(std::ostream& o, wasm::Module& module);
+std::ostream& operator<<(std::ostream& o, wasm::Expression& expression);
+std::ostream& operator<<(std::ostream& o, wasm::StackInst& inst);
+std::ostream& operator<<(std::ostream& o, wasm::StackIR& ir);
+
 } // namespace std
 
 #endif // wasm_wasm_h
diff --git a/binaryen/src/wasm/literal.cpp b/binaryen/src/wasm/literal.cpp
--- a/binaryen/src/wasm/literal.cpp
+++ b/binaryen/src/wasm/literal.cpp
@@ -37,6 +37,11 @@
     assert(type != Type::unreachable && (!type.isRef() || type.isNullable()));
     if (type.isException()) {
       new (&exn) std::unique_ptr<ExceptionPackage>();
+    } else if (isGCData()) {
+      new (&gcData) std::shared_ptr<GCData>();
+    } else if (type.isRtt()) {
+      // Allocate a new RttSupers (with no data).
+      new (&rttSupers) auto(std::make_unique<RttSupers>());
     } else {
       memset(&v128, 0, 16);
     }
@@ -47,6 +52,19 @@
   memcpy(&v128, init, 16);
 }
 
+Literal::Literal(std::shared_ptr<GCData> gcData, Type type)
+  : gcData(gcData), type(type) {
+  // Null data is only allowed if nullable.
+  assert(gcData || type.isNullable());
+  // The type must be a proper type for GC data.
+  assert(isGCData());
+}
+
+Literal::Literal(std::unique_ptr<RttSupers>&& rttSupers, Type type)
+  : rttSupers(std::move(rttSupers)), type(type) {
+  assert(type.isRtt());
+}
+
 Literal::Literal(const Literal& other) : type(other.type) {
   if (type.isException()) {
     // Avoid calling the destructor on an uninitialized value
@@ -55,8 +73,13 @@
     } else {
       new (&exn) std::unique_ptr<ExceptionPackage>();
     }
+  } else if (other.isGCData()) {
+    new (&gcData) std::shared_ptr<GCData>(other.gcData);
   } else if (type.isFunction()) {
     func = other.func;
+  } else if (type.isRtt()) {
+    // Allocate a new RttSupers with a copy of the other's data.
+    new (&rttSupers) auto(std::make_unique<RttSupers>(*other.rttSupers));
   } else {
     TODO_SINGLE_COMPOUND(type);
     switch (type.getBasic()) {
@@ -86,6 +109,21 @@
   }
 }
 
+Literal::~Literal() {
+  if (type.isException()) {
+    exn.~unique_ptr();
+  } else if (isGCData()) {
+    gcData.~shared_ptr();
+  } else if (type.isRtt()) {
+    rttSupers.~unique_ptr();
+  } else if (type.isFunction()) {
+    // Nothing special to do.
+  } else {
+    // Basic types need no special handling.
+    assert(type.isBasic());
+  }
+}
+
 Literal& Literal::operator=(const Literal& other) {
   if (this != &other) {
     this->~Literal();
@@ -162,6 +200,8 @@
     } else {
       return makeNull(type);
     }
+  } else if (type.isRtt()) {
+    return Literal(type);
   } else {
     return makeFromInt32(0, type);
   }
@@ -189,6 +229,16 @@
   return *exn;
 }
 
+std::shared_ptr<GCData> Literal::getGCData() const {
+  assert(isGCData());
+  return gcData;
+}
+
+const RttSupers& Literal::getRttSupers() const {
+  assert(type.isRtt());
+  return *rttSupers;
+}
+
 Literal Literal::castToF32() {
   assert(type == Type::i32);
   Literal ret(Type::f32);
@@ -322,7 +372,7 @@
   } else if (type.isRef()) {
     return compareRef();
   } else if (type.isRtt()) {
-    WASM_UNREACHABLE("TODO: rtt literals");
+    return *rttSupers == *other.rttSupers;
   }
   WASM_UNREACHABLE("unexpected type");
 }
@@ -422,58 +472,72 @@
 
 std::ostream& operator<<(std::ostream& o, Literal literal) {
   prepareMinorColor(o);
-  TODO_SINGLE_COMPOUND(literal.type);
-  switch (literal.type.getBasic()) {
-    case Type::none:
-      o << "?";
-      break;
-    case Type::i32:
-      o << literal.geti32();
-      break;
-    case Type::i64:
-      o << literal.geti64();
-      break;
-    case Type::f32:
-      literal.printFloat(o, literal.getf32());
-      break;
-    case Type::f64:
-      literal.printDouble(o, literal.getf64());
-      break;
-    case Type::v128:
-      o << "i32x4 ";
-      literal.printVec128(o, literal.getv128());
-      break;
-    case Type::funcref:
-      if (literal.isNull()) {
-        o << "funcref(null)";
-      } else {
-        o << "funcref(" << literal.getFunc() << ")";
-      }
-      break;
-    case Type::externref:
-      assert(literal.isNull() && "unexpected non-null externref literal");
-      o << "externref(null)";
-      break;
-    case Type::exnref:
-      if (literal.isNull()) {
-        o << "exnref(null)";
-      } else {
-        o << "exnref(" << literal.getExceptionPackage() << ")";
-      }
-      break;
-    case Type::anyref:
-      assert(literal.isNull() && "unexpected non-null anyref literal");
-      o << "anyref(null)";
-      break;
-    case Type::eqref:
-      assert(literal.isNull() && "unexpected non-null eqref literal");
-      o << "eqref(null)";
-      break;
-    case Type::i31ref:
-      o << "i31ref(" << literal.geti31() << ")";
-      break;
-    case Type::unreachable:
-      WASM_UNREACHABLE("invalid type");
+  if (literal.type.isFunction()) {
+    if (literal.isNull()) {
+      o << "funcref(null)";
+    } else {
+      o << "funcref(" << literal.getFunc() << ")";
+    }
+  } else if (literal.isGCData()) {
+    auto data = literal.getGCData();
+    if (data) {
+      o << "[ref " << data->rtt << ' ' << data->values << ']';
+    } else {
+      o << "[ref null " << literal.type << ']';
+    }
+  } else if (literal.type.isRtt()) {
+    o << "[rtt ";
+    for (Type super : literal.getRttSupers()) {
+      o << super << " :> ";
+    }
+    o << literal.type << ']';
+  } else {
+    TODO_SINGLE_COMPOUND(literal.type);
+    switch (literal.type.getBasic()) {
+      case Type::none:
+        o << "?";
+        break;
+      case Type::i32:
+        o << literal.geti32();
+        break;
+      case Type::i64:
+        o << literal.geti64();
+        break;
+      case Type::f32:
+        literal.printFloat(o, literal.getf32());
+        break;
+      case Type::f64:
+        literal.printDouble(o, literal.getf64());
+        break;
+      case Type::v128:
+        o << "i32x4 ";
+        literal.printVec128(o, literal.getv128());
+        break;
+      case Type::externref:
+        assert(literal.isNull() && "unexpected non-null externref literal");
+        o << "externref(null)";
+        break;
+      case Type::exnref:
+        if (literal.isNull()) {
+          o << "exnref(null)";
+        } else {
+          o << "exnref(" << literal.getExceptionPackage() << ")";
+        }
+        break;
+      case Type::anyref:
+        assert(literal.isNull() && "unexpected non-null anyref literal");
+        o << "anyref(null)";
+        break;
+      case Type::eqref:
+        assert(literal.isNull() && "unexpected non-null eqref literal");
+        o << "eqref(null)";
+        break;
+      case Type::i31ref:
+        o << "i31ref(" << literal.geti31() << ")";
+        break;
+      default:
+        WASM_UNREACHABLE("invalid type");
+    }
   }
   restoreNormalColor(o);
   return o;
@@ -837,6 +901,40 @@
   return Literal(float(getf64()));
 }
 
+// Wasm has nondeterministic rules for NaN propagation in some operations. For
+// example. f32.neg is deterministic and just flips the sign, even of a NaN, but
+// f32.add is nondeterministic, and if one or more of the inputs is a NaN, then
+//
+//  * if all NaNs are canonical NaNs, the output is some arbitrary canonical NaN
+//  * otherwise the output is some arbitrary arithmetic NaN
+//
+// (canonical = NaN payload is 1000..000; arithmetic: 1???..???, that is, the
+// high bit is 1 and all others can be 0 or 1)
+//
+// For many things we don't need to care, and can just do a normal C++ add for
+// an f32.add, for example - the wasm rules are specified so that things like
+// that just work (in order for such math to be fast). However, for our
+// optimizer, it is useful to "standardize" NaNs when there is nondeterminism.
+// That is, when there are multiple valid outputs, it's nice to emit the same
+// one consistently, so that it doesn't look like the optimization changed
+// something. In other words, if the valid output of an expression is a set of
+// valid NaNs, and after optimization the output is still that same set, then
+// the optimization is valid. And if the interpreter picks the same NaN in both
+// cases from that identical set then nothing looks wrong to the fuzzer.
+template<typename T> static Literal standardizeNaN(T result) {
+  if (!std::isnan(result)) {
+    return Literal(result);
+  }
+  // Pick a simple canonical payload, and positive.
+  if (sizeof(T) == 4) {
+    return Literal(Literal(uint32_t(0x7fc00000u)).reinterpretf32());
+  } else if (sizeof(T) == 8) {
+    return Literal(Literal(uint64_t(0x7ff8000000000000ull)).reinterpretf64());
+  } else {
+    WASM_UNREACHABLE("invalid float");
+  }
+}
+
 Literal Literal::add(const Literal& other) const {
   switch (type.getBasic()) {
     case Type::i32:
@@ -844,9 +942,9 @@
     case Type::i64:
       return Literal(uint64_t(i64) + uint64_t(other.i64));
     case Type::f32:
-      return Literal(getf32() + other.getf32());
+      return standardizeNaN(getf32() + other.getf32());
     case Type::f64:
-      return Literal(getf64() + other.getf64());
+      return standardizeNaN(getf64() + other.getf64());
     case Type::v128:
     case Type::funcref:
     case Type::externref:
@@ -868,9 +966,9 @@
     case Type::i64:
       return Literal(uint64_t(i64) - uint64_t(other.i64));
     case Type::f32:
-      return Literal(getf32() - other.getf32());
+      return standardizeNaN(getf32() - other.getf32());
     case Type::f64:
-      return Literal(getf64() - other.getf64());
+      return standardizeNaN(getf64() - other.getf64());
     case Type::v128:
     case Type::funcref:
     case Type::externref:
@@ -963,9 +1061,9 @@
     case Type::i64:
       return Literal(uint64_t(i64) * uint64_t(other.i64));
     case Type::f32:
-      return Literal(getf32() * other.getf32());
+      return standardizeNaN(getf32() * other.getf32());
     case Type::f64:
-      return Literal(getf64() * other.getf64());
+      return standardizeNaN(getf64() * other.getf64());
     case Type::v128:
     case Type::funcref:
     case Type::externref:
@@ -989,10 +1087,8 @@
         case FP_ZERO:
           switch (std::fpclassify(lhs)) {
             case FP_NAN:
-              return Literal(setQuietNaN(lhs));
             case FP_ZERO:
-              return Literal(
-                std::copysign(std::numeric_limits<float>::quiet_NaN(), sign));
+              return standardizeNaN(lhs / rhs);
             case FP_NORMAL:    // fallthrough
             case FP_SUBNORMAL: // fallthrough
             case FP_INFINITE:
@@ -1005,7 +1101,7 @@
         case FP_INFINITE: // fallthrough
         case FP_NORMAL:   // fallthrough
         case FP_SUBNORMAL:
-          return Literal(lhs / rhs);
+          return standardizeNaN(lhs / rhs);
         default:
           WASM_UNREACHABLE("invalid fp classification");
       }
@@ -1017,10 +1113,8 @@
         case FP_ZERO:
           switch (std::fpclassify(lhs)) {
             case FP_NAN:
-              return Literal(setQuietNaN(lhs));
             case FP_ZERO:
-              return Literal(
-                std::copysign(std::numeric_limits<double>::quiet_NaN(), sign));
+              return standardizeNaN(lhs / rhs);
             case FP_NORMAL:    // fallthrough
             case FP_SUBNORMAL: // fallthrough
             case FP_INFINITE:
@@ -1033,7 +1127,7 @@
         case FP_INFINITE: // fallthrough
         case FP_NORMAL:   // fallthrough
         case FP_SUBNORMAL:
-          return Literal(lhs / rhs);
+          return standardizeNaN(lhs / rhs);
         default:
           WASM_UNREACHABLE("invalid fp classification");
       }
@@ -1380,39 +1474,29 @@
   switch (type.getBasic()) {
     case Type::f32: {
       auto l = getf32(), r = other.getf32();
-      if (l == r && l == 0) {
-        return Literal(std::signbit(l) ? l : r);
+      if (std::isnan(l)) {
+        return standardizeNaN(l);
       }
-      auto result = std::min(l, r);
-      bool lnan = std::isnan(l), rnan = std::isnan(r);
-      if (!std::isnan(result) && !lnan && !rnan) {
-        return Literal(result);
+      if (std::isnan(r)) {
+        return standardizeNaN(r);
       }
-      if (!lnan && !rnan) {
-        return Literal((int32_t)0x7fc00000).castToF32();
+      if (l == r && l == 0) {
+        return Literal(std::signbit(l) ? l : r);
       }
-      return Literal(lnan ? l : r)
-        .castToI32()
-        .or_(Literal(0xc00000))
-        .castToF32();
+      return Literal(std::min(l, r));
     }
     case Type::f64: {
       auto l = getf64(), r = other.getf64();
-      if (l == r && l == 0) {
-        return Literal(std::signbit(l) ? l : r);
+      if (std::isnan(l)) {
+        return standardizeNaN(l);
       }
-      auto result = std::min(l, r);
-      bool lnan = std::isnan(l), rnan = std::isnan(r);
-      if (!std::isnan(result) && !lnan && !rnan) {
-        return Literal(result);
+      if (std::isnan(r)) {
+        return standardizeNaN(r);
       }
-      if (!lnan && !rnan) {
-        return Literal((int64_t)0x7ff8000000000000LL).castToF64();
+      if (l == r && l == 0) {
+        return Literal(std::signbit(l) ? l : r);
       }
-      return Literal(lnan ? l : r)
-        .castToI64()
-        .or_(Literal(int64_t(0x8000000000000LL)))
-        .castToF64();
+      return Literal(std::min(l, r));
     }
     default:
       WASM_UNREACHABLE("unexpected type");
@@ -1423,39 +1507,29 @@
   switch (type.getBasic()) {
     case Type::f32: {
       auto l = getf32(), r = other.getf32();
-      if (l == r && l == 0) {
-        return Literal(std::signbit(l) ? r : l);
+      if (std::isnan(l)) {
+        return standardizeNaN(l);
       }
-      auto result = std::max(l, r);
-      bool lnan = std::isnan(l), rnan = std::isnan(r);
-      if (!std::isnan(result) && !lnan && !rnan) {
-        return Literal(result);
+      if (std::isnan(r)) {
+        return standardizeNaN(r);
       }
-      if (!lnan && !rnan) {
-        return Literal((int32_t)0x7fc00000).castToF32();
+      if (l == r && l == 0) {
+        return Literal(std::signbit(l) ? r : l);
       }
-      return Literal(lnan ? l : r)
-        .castToI32()
-        .or_(Literal(0xc00000))
-        .castToF32();
+      return Literal(std::max(l, r));
     }
     case Type::f64: {
       auto l = getf64(), r = other.getf64();
-      if (l == r && l == 0) {
-        return Literal(std::signbit(l) ? r : l);
+      if (std::isnan(l)) {
+        return standardizeNaN(l);
       }
-      auto result = std::max(l, r);
-      bool lnan = std::isnan(l), rnan = std::isnan(r);
-      if (!std::isnan(result) && !lnan && !rnan) {
-        return Literal(result);
+      if (std::isnan(r)) {
+        return standardizeNaN(r);
       }
-      if (!lnan && !rnan) {
-        return Literal((int64_t)0x7ff8000000000000LL).castToF64();
+      if (l == r && l == 0) {
+        return Literal(std::signbit(l) ? r : l);
       }
-      return Literal(lnan ? l : r)
-        .castToI64()
-        .or_(Literal(int64_t(0x8000000000000LL)))
-        .castToF64();
+      return Literal(std::max(l, r));
     }
     default:
       WASM_UNREACHABLE("unexpected type");
@@ -1558,7 +1632,8 @@
   return Literal(bytes);
 }
 
-template<Type::BasicID Ty, int Lanes> static Literal splat(const Literal& val) {
+template<Type::BasicType Ty, int Lanes>
+static Literal splat(const Literal& val) {
   assert(val.type == Ty);
   LaneArray<Lanes> lanes;
   lanes.fill(val);
@@ -1653,6 +1728,9 @@
 Literal Literal::negI8x16() const {
   return unary<16, &Literal::getLanesUI8x16, &Literal::neg>(*this);
 }
+Literal Literal::popcntI8x16() const {
+  return unary<16, &Literal::getLanesUI8x16, &Literal::popCount>(*this);
+}
 Literal Literal::negI16x8() const {
   return unary<8, &Literal::getLanesUI16x8, &Literal::neg>(*this);
 }
@@ -1790,12 +1868,6 @@
 Literal Literal::bitmaskI32x4() const {
   return bitmask<4, &Literal::getLanesI32x4>(*this);
 }
-Literal Literal::anyTrueI64x2() const {
-  return any_true<2, &Literal::getLanesI64x2>(*this);
-}
-Literal Literal::allTrueI64x2() const {
-  return all_true<2, &Literal::getLanesI64x2>(*this);
-}
 
 template<int Lanes,
          LaneArray<Lanes> (Literal::*IntoLanes)() const,
@@ -1953,6 +2025,10 @@
 Literal Literal::geUI32x4(const Literal& other) const {
   return compare<4, &Literal::getLanesI32x4, &Literal::geU>(*this, other);
 }
+Literal Literal::eqI64x2(const Literal& other) const {
+  return compare<2, &Literal::getLanesI64x2, &Literal::eq, int64_t>(*this,
+                                                                    other);
+}
 Literal Literal::eqF32x4(const Literal& other) const {
   return compare<4, &Literal::getLanesF32x4, &Literal::eq>(*this, other);
 }
@@ -2097,6 +2173,9 @@
 Literal Literal::avgrUI16x8(const Literal& other) const {
   return binary<8, &Literal::getLanesUI16x8, &Literal::avgrUInt>(*this, other);
 }
+Literal Literal::q15MulrSatSI16x8(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement Q15 rounding, saturating multiplication");
+}
 Literal Literal::addI32x4(const Literal& other) const {
   return binary<4, &Literal::getLanesI32x4, &Literal::add>(*this, other);
 }
@@ -2274,6 +2353,43 @@
   return widen<4, &Literal::getLanesUI16x8, LaneOrder::High>(*this);
 }
 
+Literal Literal::extMulLowSI16x8(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulHighSI16x8(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulLowUI16x8(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulHighUI16x8(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulLowSI32x4(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulHighSI32x4(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulLowUI32x4(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulHighUI32x4(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulLowSI64x2(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulHighSI64x2(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulLowUI64x2(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+Literal Literal::extMulHighUI64x2(const Literal& other) const {
+  WASM_UNREACHABLE("TODO: implement SIMD extending multiplications");
+}
+
 Literal Literal::swizzleVec8x16(const Literal& other) const {
   auto lanes = getLanesUI8x16();
   auto indices = other.getLanesUI8x16();
@@ -2283,6 +2399,33 @@
     result[i] = index >= 16 ? Literal(int32_t(0)) : lanes[index];
   }
   return Literal(result);
+}
+
+bool Literal::isSubRtt(const Literal& other) const {
+  assert(type.isRtt() && other.type.isRtt());
+  // For this literal to be a sub-rtt of the other rtt, the supers must be a
+  // superset. That is, if other is a->b->c then we should be a->b->c as well
+  // with possibly ->d->.. added. The rttSupers array represents those chains,
+  // but only the supers, which means the last item in the chain is simply the
+  // type of the literal.
+  const auto& supers = getRttSupers();
+  const auto& otherSupers = other.getRttSupers();
+  if (otherSupers.size() > supers.size()) {
+    return false;
+  }
+  for (Index i = 0; i < otherSupers.size(); i++) {
+    if (supers[i] != otherSupers[i]) {
+      return false;
+    }
+  }
+  // If we have more supers than other, compare that extra super. Otherwise,
+  // we have the same amount of supers, and must be completely identical to
+  // other.
+  if (otherSupers.size() < supers.size()) {
+    return other.type == supers[otherSupers.size()];
+  } else {
+    return other.type == type;
+  }
 }
 
 } // namespace wasm
diff --git a/binaryen/src/wasm/wasm-binary.cpp b/binaryen/src/wasm/wasm-binary.cpp
--- a/binaryen/src/wasm/wasm-binary.cpp
+++ b/binaryen/src/wasm/wasm-binary.cpp
@@ -31,7 +31,7 @@
 void WasmBinaryWriter::prepare() {
   // Collect function types and their frequencies. Collect information in each
   // function in parallel, then merge.
-  ModuleUtils::collectSignatures(*wasm, types, typeIndices);
+  ModuleUtils::collectHeapTypes(*wasm, types, typeIndices);
   importInfo = wasm::make_unique<ImportInfo>(*wasm);
 }
 
@@ -215,14 +215,29 @@
   auto start = startSection(BinaryConsts::Section::Type);
   o << U32LEB(types.size());
   for (Index i = 0; i < types.size(); ++i) {
-    Signature& sig = types[i];
-    BYN_TRACE("write " << sig.params << " -> " << sig.results << std::endl);
-    o << S32LEB(BinaryConsts::EncodedType::Func);
-    for (auto& sigType : {sig.params, sig.results}) {
-      o << U32LEB(sigType.size());
-      for (const auto& type : sigType) {
-        o << binaryType(type);
+    auto type = types[i];
+    BYN_TRACE("write " << type << std::endl);
+    if (type.isSignature()) {
+      o << S32LEB(BinaryConsts::EncodedType::Func);
+      auto sig = type.getSignature();
+      for (auto& sigType : {sig.params, sig.results}) {
+        o << U32LEB(sigType.size());
+        for (const auto& type : sigType) {
+          writeType(type);
+        }
       }
+    } else if (type.isStruct()) {
+      o << S32LEB(BinaryConsts::EncodedType::Struct);
+      auto fields = type.getStruct().fields;
+      o << U32LEB(fields.size());
+      for (const auto& field : fields) {
+        writeField(field);
+      }
+    } else if (type.isArray()) {
+      o << S32LEB(BinaryConsts::EncodedType::Array);
+      writeField(type.getArray().element);
+    } else {
+      WASM_UNREACHABLE("TODO GC type writing");
     }
   }
   finishSection(start);
@@ -250,7 +265,7 @@
     BYN_TRACE("write one global\n");
     writeImportHeader(global);
     o << U32LEB(int32_t(ExternalKind::Global));
-    o << binaryType(global->type);
+    writeType(global->type);
     o << U32LEB(global->mutable_);
   });
   ModuleUtils::iterImportedEvents(*wasm, [&](Event* event) {
@@ -389,7 +404,7 @@
     BYN_TRACE("write one\n");
     size_t i = 0;
     for (const auto& t : global->type) {
-      o << binaryType(t);
+      writeType(t);
       o << U32LEB(global->mutable_);
       if (global->type.size() == 1) {
         writeExpression(global->init);
@@ -490,9 +505,14 @@
   return it->second;
 }
 
-uint32_t WasmBinaryWriter::getTypeIndex(Signature sig) const {
-  auto it = typeIndices.find(sig);
-  assert(it != typeIndices.end());
+uint32_t WasmBinaryWriter::getTypeIndex(HeapType type) const {
+  auto it = typeIndices.find(type);
+#ifndef NDEBUG
+  if (it == typeIndices.end()) {
+    std::cout << "Missing type: " << type << '\n';
+    assert(0);
+  }
+#endif
   return it->second;
 }
 
@@ -628,7 +648,7 @@
   }
 
   // table names
-  if (wasm->table.exists && wasm->table.name.is()) {
+  if (wasm->table.exists && wasm->table.hasExplicitName) {
     auto substart =
       startSubsection(BinaryConsts::UserSections::Subsection::NameTable);
     o << U32LEB(1) << U32LEB(0); // currently exactly 1 table at index 0
@@ -637,7 +657,7 @@
   }
 
   // memory names
-  if (wasm->memory.exists && wasm->memory.name.is()) {
+  if (wasm->memory.exists && wasm->memory.hasExplicitName) {
     auto substart =
       startSubsection(BinaryConsts::UserSections::Subsection::NameMemory);
     o << U32LEB(1) << U32LEB(0); // currently exactly 1 memory at index 0
@@ -650,7 +670,7 @@
     std::vector<std::pair<Index, Global*>> globalsWithNames;
     Index checked = 0;
     auto check = [&](Global* curr) {
-      if (curr->name.is()) {
+      if (curr->hasExplicitName) {
         globalsWithNames.push_back({checked, curr});
       }
       checked++;
@@ -670,7 +690,31 @@
     }
   }
 
-  // TODO: label, type, element and data names
+  // memory names
+  if (wasm->memory.exists) {
+    Index count = 0;
+    for (auto& seg : wasm->memory.segments) {
+      if (seg.name.is()) {
+        count++;
+      }
+    }
+
+    if (count) {
+      auto substart =
+        startSubsection(BinaryConsts::UserSections::Subsection::NameData);
+      o << U32LEB(count);
+      for (Index i = 0; i < wasm->memory.segments.size(); i++) {
+        auto& seg = wasm->memory.segments[i];
+        if (seg.name.is()) {
+          o << U32LEB(i);
+          writeEscapedName(seg.name.str);
+        }
+      }
+      finishSubsection(substart);
+    }
+  }
+
+  // TODO: label, type, and element names
   // see: https://github.com/WebAssembly/extended-name-section
 
   finishSection(start);
@@ -799,6 +843,8 @@
         return BinaryConsts::UserSections::GCFeature;
       case FeatureSet::Memory64:
         return BinaryConsts::UserSections::Memory64Feature;
+      case FeatureSet::TypedFunctionReferences:
+        return BinaryConsts::UserSections::TypedFunctionReferencesFeature;
       default:
         WASM_UNREACHABLE("unexpected feature flag");
     }
@@ -865,7 +911,6 @@
 void WasmBinaryWriter::writeDebugLocationEnd(Expression* curr, Function* func) {
   if (func && !func->expressionLocations.empty()) {
     auto& span = binaryLocations.expressions.at(curr);
-    assert(span.end == 0);
     span.end = o.size();
   }
 }
@@ -951,6 +996,121 @@
   }
 }
 
+void WasmBinaryWriter::writeType(Type type) {
+  if (type.isRef() && !type.isBasic()) {
+    if (type.isNullable()) {
+      o << S32LEB(BinaryConsts::EncodedType::nullable);
+    } else {
+      o << S32LEB(BinaryConsts::EncodedType::nonnullable);
+    }
+    writeHeapType(type.getHeapType());
+    return;
+  }
+  if (type.isRtt()) {
+    auto rtt = type.getRtt();
+    if (rtt.hasDepth()) {
+      o << S32LEB(BinaryConsts::EncodedType::rtt_n);
+      o << U32LEB(rtt.depth);
+    } else {
+      o << S32LEB(BinaryConsts::EncodedType::rtt);
+    }
+    writeHeapType(rtt.heapType);
+    return;
+  }
+  int ret = 0;
+  TODO_SINGLE_COMPOUND(type);
+  switch (type.getBasic()) {
+    // None only used for block signatures. TODO: Separate out?
+    case Type::none:
+      ret = BinaryConsts::EncodedType::Empty;
+      break;
+    case Type::i32:
+      ret = BinaryConsts::EncodedType::i32;
+      break;
+    case Type::i64:
+      ret = BinaryConsts::EncodedType::i64;
+      break;
+    case Type::f32:
+      ret = BinaryConsts::EncodedType::f32;
+      break;
+    case Type::f64:
+      ret = BinaryConsts::EncodedType::f64;
+      break;
+    case Type::v128:
+      ret = BinaryConsts::EncodedType::v128;
+      break;
+    case Type::funcref:
+      ret = BinaryConsts::EncodedType::funcref;
+      break;
+    case Type::externref:
+      ret = BinaryConsts::EncodedType::externref;
+      break;
+    case Type::exnref:
+      ret = BinaryConsts::EncodedType::exnref;
+      break;
+    case Type::anyref:
+      ret = BinaryConsts::EncodedType::anyref;
+      break;
+    case Type::eqref:
+      ret = BinaryConsts::EncodedType::eqref;
+      break;
+    case Type::i31ref:
+      ret = BinaryConsts::EncodedType::i31ref;
+      break;
+    default:
+      WASM_UNREACHABLE("unexpected type");
+  }
+  o << S32LEB(ret);
+}
+
+void WasmBinaryWriter::writeHeapType(HeapType type) {
+  if (type.isSignature() || type.isStruct() || type.isArray()) {
+    o << S64LEB(getTypeIndex(type)); // TODO: Actually s33
+    return;
+  }
+  int ret = 0;
+  if (type.isBasic()) {
+    switch (type.getBasic()) {
+      case HeapType::func:
+        ret = BinaryConsts::EncodedHeapType::func;
+        break;
+      case HeapType::ext:
+        ret = BinaryConsts::EncodedHeapType::extern_;
+        break;
+      case HeapType::exn:
+        ret = BinaryConsts::EncodedHeapType::exn;
+        break;
+      case HeapType::any:
+        ret = BinaryConsts::EncodedHeapType::any;
+        break;
+      case HeapType::eq:
+        ret = BinaryConsts::EncodedHeapType::eq;
+        break;
+      case HeapType::i31:
+        ret = BinaryConsts::EncodedHeapType::i31;
+        break;
+    }
+  } else {
+    WASM_UNREACHABLE("TODO: compound GC types");
+  }
+  o << S64LEB(ret); // TODO: Actually s33
+}
+
+void WasmBinaryWriter::writeField(const Field& field) {
+  if (field.type == Type::i32 && field.packedType != Field::not_packed) {
+    if (field.packedType == Field::i8) {
+      o << S32LEB(BinaryConsts::EncodedType::i8);
+    } else if (field.packedType == Field::i16) {
+      o << S32LEB(BinaryConsts::EncodedType::i16);
+    } else {
+      WASM_UNREACHABLE("invalid packed type");
+    }
+  } else {
+    writeType(field.type);
+  }
+  o << U32LEB(field.mutable_);
+}
+
 // reader
 
 bool WasmBinaryBuilder::hasDWARFSections() {
@@ -1021,7 +1181,7 @@
         readMemory();
         break;
       case BinaryConsts::Section::Type:
-        readSignatures();
+        readTypes();
         break;
       case BinaryConsts::Section::Import:
         readImports();
@@ -1216,17 +1376,17 @@
   return ret.value;
 }
 
-Type WasmBinaryBuilder::getType() {
-  int type = getS32LEB();
+uint64_t WasmBinaryBuilder::getUPtrLEB() {
+  return wasm.memory.is64() ? getU64LEB() : getU32LEB();
+}
+
+Type WasmBinaryBuilder::getType(int initial) {
   // Single value types are negative; signature indices are non-negative
-  if (type >= 0) {
-    // TODO: Handle block input types properly
-    if (size_t(type) >= signatures.size()) {
-      throwError("invalid signature index: " + std::to_string(type));
-    }
-    return signatures[type].results;
+  if (initial >= 0) {
+    // TODO: Handle block input types properly.
+    return getSignatureByTypeIndex(initial).results;
   }
-  switch (type) {
+  switch (initial) {
     // None only used for block signatures. TODO: Separate out?
     case BinaryConsts::EncodedType::Empty:
       return Type::none;
@@ -1250,42 +1410,87 @@
       return Type::anyref;
     case BinaryConsts::EncodedType::eqref:
       return Type::eqref;
+    case BinaryConsts::EncodedType::nullable:
+      return Type(getHeapType(), Nullable);
+    case BinaryConsts::EncodedType::nonnullable:
+      // FIXME: for now, force all inputs to be nullable
+      return Type(getHeapType(), Nullable);
     case BinaryConsts::EncodedType::i31ref:
-      return Type::i31ref;
+      // FIXME: for now, force all inputs to be nullable
+      return Type(HeapType::BasicHeapType::i31, Nullable);
+    case BinaryConsts::EncodedType::rtt_n: {
+      auto depth = getU32LEB();
+      auto heapType = getHeapType();
+      return Type(Rtt(depth, heapType));
+    }
+    case BinaryConsts::EncodedType::rtt: {
+      return Type(Rtt(getHeapType()));
+    }
     default:
-      throwError("invalid wasm type: " + std::to_string(type));
+      throwError("invalid wasm type: " + std::to_string(initial));
   }
   WASM_UNREACHABLE("unexpected type");
 }
 
+Type WasmBinaryBuilder::getType() { return getType(getS32LEB()); }
+
 HeapType WasmBinaryBuilder::getHeapType() {
-  int type = getS32LEB(); // TODO: Actually encoded as s33
+  auto type = getS64LEB(); // TODO: Actually s33
   // Single heap types are negative; heap type indices are non-negative
   if (type >= 0) {
-    if (size_t(type) >= signatures.size()) {
+    if (size_t(type) >= types.size()) {
       throwError("invalid signature index: " + std::to_string(type));
     }
-    return HeapType(signatures[type]);
+    return types[type];
   }
   switch (type) {
     case BinaryConsts::EncodedHeapType::func:
-      return HeapType::FuncKind;
+      return HeapType::func;
     case BinaryConsts::EncodedHeapType::extern_:
-      return HeapType::ExternKind;
+      return HeapType::ext;
     case BinaryConsts::EncodedHeapType::exn:
-      return HeapType::ExnKind;
+      return HeapType::exn;
     case BinaryConsts::EncodedHeapType::any:
-      return HeapType::AnyKind;
+      return HeapType::any;
     case BinaryConsts::EncodedHeapType::eq:
-      return HeapType::EqKind;
+      return HeapType::eq;
     case BinaryConsts::EncodedHeapType::i31:
-      return HeapType::I31Kind;
+      return HeapType::i31;
     default:
       throwError("invalid wasm heap type: " + std::to_string(type));
   }
   WASM_UNREACHABLE("unexpected type");
 }
 
+Mutability WasmBinaryBuilder::getMutability() {
+  switch (getU32LEB()) {
+    case 0:
+      return Immutable;
+    case 1:
+      return Mutable;
+    default:
+      throw ParseException("Expected 0 or 1 for mutability");
+  }
+}
+
+Field WasmBinaryBuilder::getField() {
+  // The value may be a general wasm type, or one of the types only possible in
+  // a field.
+  auto initial = getS32LEB();
+  if (initial == BinaryConsts::EncodedType::i8) {
+    auto mutable_ = getMutability();
+    return Field(Field::i8, mutable_);
+  }
+  if (initial == BinaryConsts::EncodedType::i16) {
+    auto mutable_ = getMutability();
+    return Field(Field::i16, mutable_);
+  }
+  // It's a regular wasm value.
+  auto type = getType(initial);
+  auto mutable_ = getMutability();
+  return Field(type, mutable_);
+}
+
 Type WasmBinaryBuilder::getConcreteType() {
   auto type = getType();
   if (!type.isConcrete()) {
@@ -1339,12 +1544,6 @@
   }
 }
 
-void WasmBinaryBuilder::ungetInt8() {
-  assert(pos > 0);
-  BYN_TRACE("ungetInt8 (at " << pos << ")\n");
-  pos--;
-}
-
 void WasmBinaryBuilder::readHeader() {
   BYN_TRACE("== readHeader\n");
   verifyInt32(BinaryConsts::Magic);
@@ -1376,29 +1575,40 @@
                      Memory::kUnlimitedSize);
 }
 
-void WasmBinaryBuilder::readSignatures() {
-  BYN_TRACE("== readSignatures\n");
+void WasmBinaryBuilder::readTypes() {
+  BYN_TRACE("== readTypes\n");
   size_t numTypes = getU32LEB();
   BYN_TRACE("num: " << numTypes << std::endl);
   for (size_t i = 0; i < numTypes; i++) {
     BYN_TRACE("read one\n");
-    std::vector<Type> params;
-    std::vector<Type> results;
     auto form = getS32LEB();
-    if (form != BinaryConsts::EncodedType::Func) {
-      throwError("bad signature form " + std::to_string(form));
-    }
-    size_t numParams = getU32LEB();
-    BYN_TRACE("num params: " << numParams << std::endl);
-    for (size_t j = 0; j < numParams; j++) {
-      params.push_back(getConcreteType());
-    }
-    auto numResults = getU32LEB();
-    BYN_TRACE("num results: " << numResults << std::endl);
-    for (size_t j = 0; j < numResults; j++) {
-      results.push_back(getConcreteType());
+    if (form == BinaryConsts::EncodedType::Func) {
+      std::vector<Type> params;
+      std::vector<Type> results;
+      size_t numParams = getU32LEB();
+      BYN_TRACE("num params: " << numParams << std::endl);
+      for (size_t j = 0; j < numParams; j++) {
+        params.push_back(getConcreteType());
+      }
+      auto numResults = getU32LEB();
+      BYN_TRACE("num results: " << numResults << std::endl);
+      for (size_t j = 0; j < numResults; j++) {
+        results.push_back(getConcreteType());
+      }
+      types.emplace_back(Signature(Type(params), Type(results)));
+    } else if (form == BinaryConsts::EncodedType::Struct) {
+      FieldList fields;
+      size_t numFields = getU32LEB();
+      BYN_TRACE("num fields: " << numFields << std::endl);
+      for (size_t j = 0; j < numFields; j++) {
+        fields.push_back(getField());
+      }
+      types.emplace_back(Struct(fields));
+    } else if (form == BinaryConsts::EncodedType::Array) {
+      types.emplace_back(Array(getField()));
+    } else {
+      throwError("bad type form " + std::to_string(form));
     }
-    signatures.emplace_back(Type(params), Type(results));
   }
 }
 
@@ -1450,6 +1660,11 @@
   size_t num = getU32LEB();
   BYN_TRACE("num: " << num << std::endl);
   Builder builder(wasm);
+  size_t tableCounter = 0;
+  size_t memoryCounter = 0;
+  size_t functionCounter = 0;
+  size_t globalCounter = 0;
+  size_t eventCounter = 0;
   for (size_t i = 0; i < num; i++) {
     BYN_TRACE("read one\n");
     auto module = getInlineString();
@@ -1460,23 +1675,21 @@
     // could occur later due to the names section.
     switch (kind) {
       case ExternalKind::Function: {
-        auto name = Name(std::string("fimport$") + std::to_string(i));
+        Name name(std::string("fimport$") + std::to_string(functionCounter++));
         auto index = getU32LEB();
-        if (index >= signatures.size()) {
-          throwError("invalid function index " + std::to_string(index) + " / " +
-                     std::to_string(signatures.size()));
-        }
-        auto* curr = builder.makeFunction(name, signatures[index], {});
+        auto curr =
+          builder.makeFunction(name, getSignatureByTypeIndex(index), {});
         curr->module = module;
         curr->base = base;
-        wasm.addFunction(curr);
-        functionImports.push_back(curr);
+        functionImports.push_back(curr.get());
+        wasm.addFunction(std::move(curr));
         break;
       }
       case ExternalKind::Table: {
+        Name name(std::string("timport$") + std::to_string(tableCounter++));
         wasm.table.module = module;
         wasm.table.base = base;
-        wasm.table.name = Name(std::string("timport$") + std::to_string(i));
+        wasm.table.name = name;
         auto elementType = getS32LEB();
         WASM_UNUSED(elementType);
         if (elementType != BinaryConsts::EncodedType::funcref) {
@@ -1499,9 +1712,10 @@
         break;
       }
       case ExternalKind::Memory: {
+        Name name(std::string("mimport$") + std::to_string(memoryCounter++));
         wasm.memory.module = module;
         wasm.memory.base = base;
-        wasm.memory.name = Name(std::string("mimport$") + std::to_string(i));
+        wasm.memory.name = name;
         wasm.memory.exists = true;
         getResizableLimits(wasm.memory.initial,
                            wasm.memory.max,
@@ -1511,32 +1725,29 @@
         break;
       }
       case ExternalKind::Global: {
-        auto name = Name(std::string("gimport$") + std::to_string(i));
+        Name name(std::string("gimport$") + std::to_string(globalCounter++));
         auto type = getConcreteType();
         auto mutable_ = getU32LEB();
-        auto* curr =
+        auto curr =
           builder.makeGlobal(name,
                              type,
                              nullptr,
                              mutable_ ? Builder::Mutable : Builder::Immutable);
         curr->module = module;
         curr->base = base;
-        wasm.addGlobal(curr);
-        globalImports.push_back(curr);
+        globalImports.push_back(curr.get());
+        wasm.addGlobal(std::move(curr));
         break;
       }
       case ExternalKind::Event: {
-        auto name = Name(std::string("eimport$") + std::to_string(i));
+        Name name(std::string("eimport$") + std::to_string(eventCounter++));
         auto attribute = getU32LEB();
         auto index = getU32LEB();
-        if (index >= signatures.size()) {
-          throwError("invalid event index " + std::to_string(index) + " / " +
-                     std::to_string(signatures.size()));
-        }
-        auto* curr = builder.makeEvent(name, attribute, signatures[index]);
+        auto curr =
+          builder.makeEvent(name, attribute, getSignatureByTypeIndex(index));
         curr->module = module;
         curr->base = base;
-        wasm.addEvent(curr);
+        wasm.addEvent(std::move(curr));
         break;
       }
       default: {
@@ -1564,13 +1775,34 @@
   for (size_t i = 0; i < num; i++) {
     BYN_TRACE("read one\n");
     auto index = getU32LEB();
-    if (index >= signatures.size()) {
-      throwError("invalid function type index for function");
-    }
-    functionSignatures.push_back(signatures[index]);
+    functionSignatures.push_back(getSignatureByTypeIndex(index));
   }
 }
 
+Signature WasmBinaryBuilder::getSignatureByFunctionIndex(Index index) {
+  Signature sig;
+  if (index < functionImports.size()) {
+    return functionImports[index]->sig;
+  }
+  Index adjustedIndex = index - functionImports.size();
+  if (adjustedIndex >= functionSignatures.size()) {
+    throwError("invalid function index");
+  }
+  return functionSignatures[adjustedIndex];
+}
+
+Signature WasmBinaryBuilder::getSignatureByTypeIndex(Index index) {
+  if (index >= types.size()) {
+    throwError("invalid type index " + std::to_string(index) + " / " +
+               std::to_string(types.size()));
+  }
+  auto heapType = types[index];
+  if (!heapType.isSignature()) {
+    throwError("invalid signature type " + heapType.toString());
+  }
+  return heapType.getSignature();
+}
+
 void WasmBinaryBuilder::readFunctions() {
   BYN_TRACE("== readFunctions\n");
   size_t total = getU32LEB();
@@ -2055,8 +2287,8 @@
   for (auto* func : functions) {
     wasm.addFunction(func);
   }
-  for (auto* global : globals) {
-    wasm.addGlobal(global);
+  for (auto& global : globals) {
+    wasm.addGlobal(std::move(global));
   }
 
   // now that we have names, apply things
@@ -2224,12 +2456,9 @@
     BYN_TRACE("read one\n");
     auto attribute = getU32LEB();
     auto typeIndex = getU32LEB();
-    if (typeIndex >= signatures.size()) {
-      throwError("invalid event index " + std::to_string(typeIndex) + " / " +
-                 std::to_string(signatures.size()));
-    }
-    wasm.addEvent(Builder::makeEvent(
-      "event$" + std::to_string(i), attribute, signatures[typeIndex]));
+    wasm.addEvent(Builder::makeEvent("event$" + std::to_string(i),
+                                     attribute,
+                                     getSignatureByTypeIndex(typeIndex)));
   }
 }
 
@@ -2294,9 +2523,9 @@
         }
         auto numFunctionImports = functionImports.size();
         if (index < numFunctionImports) {
-          functionImports[index]->name = name;
+          functionImports[index]->setExplicitName(name);
         } else if (index - numFunctionImports < functions.size()) {
-          functions[index - numFunctionImports]->name = name;
+          functions[index - numFunctionImports]->setExplicitName(name);
         } else {
           std::cerr << "warning: function index out of bounds in name section, "
                        "function subsection: "
@@ -2351,7 +2580,7 @@
         auto index = getU32LEB();
         auto rawName = getInlineString();
         if (index == 0) {
-          wasm.table.name = escape(rawName);
+          wasm.table.setExplicitName(escape(rawName));
         } else {
           std::cerr << "warning: table index out of bounds in name section, "
                        "table subsection: "
@@ -2365,7 +2594,7 @@
         auto index = getU32LEB();
         auto rawName = getInlineString();
         if (index == 0) {
-          wasm.memory.name = escape(rawName);
+          wasm.memory.setExplicitName(escape(rawName));
         } else {
           std::cerr << "warning: memory index out of bounds in name section, "
                        "memory subsection: "
@@ -2373,6 +2602,20 @@
                     << std::to_string(index) << std::endl;
         }
       }
+    } else if (nameType == BinaryConsts::UserSections::Subsection::NameData) {
+      auto num = getU32LEB();
+      for (size_t i = 0; i < num; i++) {
+        auto index = getU32LEB();
+        auto rawName = getInlineString();
+        if (index < wasm.memory.segments.size()) {
+          wasm.memory.segments[i].name = rawName;
+        } else {
+          std::cerr << "warning: memory index out of bounds in name section, "
+                       "memory subsection: "
+                    << std::string(rawName.str) << " at index "
+                    << std::to_string(index) << std::endl;
+        }
+      }
     } else if (nameType == BinaryConsts::UserSections::Subsection::NameGlobal) {
       auto num = getU32LEB();
       std::set<Name> usedNames;
@@ -2387,9 +2630,9 @@
         }
         auto numGlobalImports = globalImports.size();
         if (index < numGlobalImports) {
-          globalImports[index]->name = name;
+          globalImports[index]->setExplicitName(name);
         } else if (index - numGlobalImports < globals.size()) {
-          globals[index - numGlobalImports]->name = name;
+          globals[index - numGlobalImports]->setExplicitName(name);
         } else {
           std::cerr << "warning: global index out of bounds in name section, "
                        "global subsection: "
@@ -2461,6 +2704,9 @@
         wasm.features.setGC();
       } else if (name == BinaryConsts::UserSections::Memory64Feature) {
         wasm.features.setMemory64();
+      } else if (name ==
+                 BinaryConsts::UserSections::TypedFunctionReferencesFeature) {
+        wasm.features.setTypedFunctionReferences();
       }
     }
   }
@@ -2573,7 +2819,12 @@
       break;
     case BinaryConsts::End:
       curr = nullptr;
-      continueControlFlow(BinaryLocations::End, startPos);
+      // Pop the current control flow structure off the stack. If there is none
+      // then this is the "end" of the function itself, which also emits an
+      // "end" byte.
+      if (!controlFlowStack.empty()) {
+        controlFlowStack.pop_back();
+      }
       break;
     case BinaryConsts::Else:
       curr = nullptr;
@@ -2625,6 +2876,16 @@
       visitMemoryGrow(grow);
       break;
     }
+    case BinaryConsts::CallRef:
+      visitCallRef((curr = allocator.alloc<CallRef>())->cast<CallRef>());
+      break;
+    case BinaryConsts::RetCallRef: {
+      auto call = allocator.alloc<CallRef>();
+      call->isReturn = true;
+      curr = call;
+      visitCallRef(call);
+      break;
+    }
     case BinaryConsts::AtomicPrefix: {
       code = static_cast<uint8_t>(getU32LEB());
       if (maybeVisitLoad(curr, code, /*isAtomic=*/true)) {
@@ -2704,6 +2965,12 @@
       if (maybeVisitSIMDLoad(curr, opcode)) {
         break;
       }
+      if (maybeVisitSIMDLoadStoreLane(curr, opcode)) {
+        break;
+      }
+      if (maybeVisitPrefetch(curr, opcode)) {
+        break;
+      }
       throwError("invalid code after SIMD prefix: " + std::to_string(opcode));
       break;
     }
@@ -2798,22 +3065,12 @@
 void WasmBinaryBuilder::continueControlFlow(BinaryLocations::DelimiterId id,
                                             BinaryLocation pos) {
   if (DWARF && currFunction) {
-    if (controlFlowStack.empty()) {
-      // We reached the end of the function, which is also marked with an
-      // "end", like a control flow structure.
-      assert(id == BinaryLocations::End);
-      assert(pos + 1 == endOfFunction);
-      return;
-    }
     assert(!controlFlowStack.empty());
     auto currControlFlow = controlFlowStack.back();
     // We are called after parsing the byte, so we need to subtract one to
     // get its position.
     currFunction->delimiterLocations[currControlFlow][id] =
       pos - codeSectionLocation;
-    if (id == BinaryLocations::End) {
-      controlFlowStack.pop_back();
-    }
   }
 }
 
@@ -2901,8 +3158,9 @@
     }
     pushBlockElements(curr, curr->type, start);
     curr->finalize(curr->type,
-                   breakTargetNames.find(curr->name) !=
-                     breakTargetNames.end() /* hasBreak */);
+                   breakTargetNames.find(curr->name) != breakTargetNames.end()
+                     ? Block::HasBreak
+                     : Block::NoBreak);
     breakStack.pop_back();
     breakTargetNames.erase(curr->name);
   }
@@ -3034,17 +3292,7 @@
 void WasmBinaryBuilder::visitCall(Call* curr) {
   BYN_TRACE("zz node: Call\n");
   auto index = getU32LEB();
-  Signature sig;
-  if (index < functionImports.size()) {
-    auto* import = functionImports[index];
-    sig = import->sig;
-  } else {
-    Index adjustedIndex = index - functionImports.size();
-    if (adjustedIndex >= functionSignatures.size()) {
-      throwError("invalid call index");
-    }
-    sig = functionSignatures[adjustedIndex];
-  }
+  auto sig = getSignatureByFunctionIndex(index);
   auto num = sig.params.size();
   curr->operands.resize(num);
   for (size_t i = 0; i < num; i++) {
@@ -3058,10 +3306,7 @@
 void WasmBinaryBuilder::visitCallIndirect(CallIndirect* curr) {
   BYN_TRACE("zz node: CallIndirect\n");
   auto index = getU32LEB();
-  if (index >= signatures.size()) {
-    throwError("bad call_indirect function index");
-  }
-  curr->sig = signatures[index];
+  curr->sig = getSignatureByTypeIndex(index);
   auto reserved = getU32LEB();
   if (reserved != 0) {
     throwError("Invalid flags field in call_indirect");
@@ -3115,7 +3360,7 @@
     if (adjustedIndex >= globals.size()) {
       throwError("invalid global index");
     }
-    auto* glob = globals[adjustedIndex];
+    auto& glob = globals[adjustedIndex];
     curr->name = glob->name;
     curr->type = glob->type;
   }
@@ -3146,92 +3391,96 @@
     throwError("Alignment must be of a reasonable size");
   }
   alignment = Bits::pow2(rawAlignment);
-  offset = getU32LEB();
+  offset = getUPtrLEB();
 }
 
 bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out,
                                        uint8_t code,
                                        bool isAtomic) {
   Load* curr;
+  auto allocate = [&]() {
+    curr = allocator.alloc<Load>();
+    // The signed field does not matter in some cases (where the size of the
+    // load is equal to the size of the type, in which case we do not extend),
+    // but give it a default value nonetheless, to make hashing and other code
+    // simpler, so that they do not need to consider whether the sign matters or
+    // not.
+    curr->signed_ = false;
+  };
   if (!isAtomic) {
     switch (code) {
       case BinaryConsts::I32LoadMem8S:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 1;
         curr->type = Type::i32;
         curr->signed_ = true;
         break;
       case BinaryConsts::I32LoadMem8U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 1;
         curr->type = Type::i32;
-        curr->signed_ = false;
         break;
       case BinaryConsts::I32LoadMem16S:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 2;
         curr->type = Type::i32;
         curr->signed_ = true;
         break;
       case BinaryConsts::I32LoadMem16U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 2;
         curr->type = Type::i32;
-        curr->signed_ = false;
         break;
       case BinaryConsts::I32LoadMem:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 4;
         curr->type = Type::i32;
         break;
       case BinaryConsts::I64LoadMem8S:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 1;
         curr->type = Type::i64;
         curr->signed_ = true;
         break;
       case BinaryConsts::I64LoadMem8U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 1;
         curr->type = Type::i64;
-        curr->signed_ = false;
         break;
       case BinaryConsts::I64LoadMem16S:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 2;
         curr->type = Type::i64;
         curr->signed_ = true;
         break;
       case BinaryConsts::I64LoadMem16U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 2;
         curr->type = Type::i64;
-        curr->signed_ = false;
         break;
       case BinaryConsts::I64LoadMem32S:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 4;
         curr->type = Type::i64;
         curr->signed_ = true;
         break;
       case BinaryConsts::I64LoadMem32U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 4;
         curr->type = Type::i64;
-        curr->signed_ = false;
         break;
       case BinaryConsts::I64LoadMem:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 8;
         curr->type = Type::i64;
         break;
       case BinaryConsts::F32LoadMem:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 4;
         curr->type = Type::f32;
         break;
       case BinaryConsts::F64LoadMem:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 8;
         curr->type = Type::f64;
         break;
@@ -3242,44 +3491,43 @@
   } else {
     switch (code) {
       case BinaryConsts::I32AtomicLoad8U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 1;
         curr->type = Type::i32;
         break;
       case BinaryConsts::I32AtomicLoad16U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 2;
         curr->type = Type::i32;
         break;
       case BinaryConsts::I32AtomicLoad:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 4;
         curr->type = Type::i32;
         break;
       case BinaryConsts::I64AtomicLoad8U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 1;
         curr->type = Type::i64;
         break;
       case BinaryConsts::I64AtomicLoad16U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 2;
         curr->type = Type::i64;
         break;
       case BinaryConsts::I64AtomicLoad32U:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 4;
         curr->type = Type::i64;
         break;
       case BinaryConsts::I64AtomicLoad:
-        curr = allocator.alloc<Load>();
+        allocate();
         curr->bytes = 8;
         curr->type = Type::i64;
         break;
       default:
         return false;
     }
-    curr->signed_ = false;
     BYN_TRACE("zz node: AtomicLoad\n");
   }
 
@@ -3406,7 +3654,7 @@
 
   // Set curr to the given opcode, type and size.
 #define SET(opcode, optype, size)                                              \
-  curr->op = opcode;                                                           \
+  curr->op = RMW##opcode;                                                      \
   curr->type = optype;                                                         \
   curr->bytes = size
 
@@ -4139,6 +4387,10 @@
       curr = allocator.alloc<Binary>();
       curr->op = GeUVecI32x4;
       break;
+    case BinaryConsts::I64x2Eq:
+      curr = allocator.alloc<Binary>();
+      curr->op = EqVecI64x2;
+      break;
     case BinaryConsts::F32x4Eq:
       curr = allocator.alloc<Binary>();
       curr->op = EqVecF32x4;
@@ -4299,6 +4551,26 @@
       curr = allocator.alloc<Binary>();
       curr->op = AvgrUVecI16x8;
       break;
+    case BinaryConsts::I16x8Q15MulrSatS:
+      curr = allocator.alloc<Binary>();
+      curr->op = Q15MulrSatSVecI16x8;
+      break;
+    case BinaryConsts::I16x8ExtMulLowSI8x16:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulLowSVecI16x8;
+      break;
+    case BinaryConsts::I16x8ExtMulHighSI8x16:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulHighSVecI16x8;
+      break;
+    case BinaryConsts::I16x8ExtMulLowUI8x16:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulLowUVecI16x8;
+      break;
+    case BinaryConsts::I16x8ExtMulHighUI8x16:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulHighUVecI16x8;
+      break;
     case BinaryConsts::I32x4Add:
       curr = allocator.alloc<Binary>();
       curr->op = AddVecI32x4;
@@ -4331,6 +4603,22 @@
       curr = allocator.alloc<Binary>();
       curr->op = DotSVecI16x8ToVecI32x4;
       break;
+    case BinaryConsts::I32x4ExtMulLowSI16x8:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulLowSVecI32x4;
+      break;
+    case BinaryConsts::I32x4ExtMulHighSI16x8:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulHighSVecI32x4;
+      break;
+    case BinaryConsts::I32x4ExtMulLowUI16x8:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulLowUVecI32x4;
+      break;
+    case BinaryConsts::I32x4ExtMulHighUI16x8:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulHighUVecI32x4;
+      break;
     case BinaryConsts::I64x2Add:
       curr = allocator.alloc<Binary>();
       curr->op = AddVecI64x2;
@@ -4343,6 +4631,22 @@
       curr = allocator.alloc<Binary>();
       curr->op = MulVecI64x2;
       break;
+    case BinaryConsts::I64x2ExtMulLowSI32x4:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulLowSVecI64x2;
+      break;
+    case BinaryConsts::I64x2ExtMulHighSI32x4:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulHighSVecI64x2;
+      break;
+    case BinaryConsts::I64x2ExtMulLowUI32x4:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulLowUVecI64x2;
+      break;
+    case BinaryConsts::I64x2ExtMulHighUI32x4:
+      curr = allocator.alloc<Binary>();
+      curr->op = ExtMulHighUVecI64x2;
+      break;
     case BinaryConsts::F32x4Add:
       curr = allocator.alloc<Binary>();
       curr->op = AddVecF32x4;
@@ -4468,6 +4772,10 @@
       curr = allocator.alloc<Unary>();
       curr->op = NotVec128;
       break;
+    case BinaryConsts::I8x16Popcnt:
+      curr = allocator.alloc<Unary>();
+      curr->op = PopcntVecI8x16;
+      break;
     case BinaryConsts::I8x16Abs:
       curr = allocator.alloc<Unary>();
       curr->op = AbsVecI8x16;
@@ -4532,13 +4840,9 @@
       curr = allocator.alloc<Unary>();
       curr->op = NegVecI64x2;
       break;
-    case BinaryConsts::I64x2AnyTrue:
-      curr = allocator.alloc<Unary>();
-      curr->op = AnyTrueVecI64x2;
-      break;
-    case BinaryConsts::I64x2AllTrue:
+    case BinaryConsts::I64x2Bitmask:
       curr = allocator.alloc<Unary>();
-      curr->op = AllTrueVecI64x2;
+      curr->op = BitmaskVecI64x2;
       break;
     case BinaryConsts::F32x4Abs:
       curr = allocator.alloc<Unary>();
@@ -4596,6 +4900,22 @@
       curr = allocator.alloc<Unary>();
       curr->op = NearestVecF64x2;
       break;
+    case BinaryConsts::I16x8ExtAddPairWiseSI8x16:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtAddPairwiseSVecI8x16ToI16x8;
+      break;
+    case BinaryConsts::I16x8ExtAddPairWiseUI8x16:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtAddPairwiseUVecI8x16ToI16x8;
+      break;
+    case BinaryConsts::I32x4ExtAddPairWiseSI16x8:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtAddPairwiseSVecI16x8ToI32x4;
+      break;
+    case BinaryConsts::I32x4ExtAddPairWiseUI16x8:
+      curr = allocator.alloc<Unary>();
+      curr->op = ExtAddPairwiseUVecI16x8ToI32x4;
+      break;
     case BinaryConsts::I32x4TruncSatSF32x4:
       curr = allocator.alloc<Unary>();
       curr->op = TruncSatSVecF32x4ToVecI32x4;
@@ -4660,6 +4980,22 @@
       curr = allocator.alloc<Unary>();
       curr->op = WidenHighUVecI16x8ToVecI32x4;
       break;
+    case BinaryConsts::I64x2WidenLowSI32x4:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenLowSVecI32x4ToVecI64x2;
+      break;
+    case BinaryConsts::I64x2WidenHighSI32x4:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenHighSVecI32x4ToVecI64x2;
+      break;
+    case BinaryConsts::I64x2WidenLowUI32x4:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenLowUVecI32x4ToVecI64x2;
+      break;
+    case BinaryConsts::I64x2WidenHighUI32x4:
+      curr = allocator.alloc<Unary>();
+      curr->op = WidenHighUVecI32x4ToVecI64x2;
+      break;
     default:
       return false;
   }
@@ -4813,6 +5149,22 @@
       curr = allocator.alloc<SIMDTernary>();
       curr->op = Bitselect;
       break;
+    case BinaryConsts::V8x16SignSelect:
+      curr = allocator.alloc<SIMDTernary>();
+      curr->op = SignSelectVec8x16;
+      break;
+    case BinaryConsts::V16x8SignSelect:
+      curr = allocator.alloc<SIMDTernary>();
+      curr->op = SignSelectVec16x8;
+      break;
+    case BinaryConsts::V32x4SignSelect:
+      curr = allocator.alloc<SIMDTernary>();
+      curr->op = SignSelectVec32x4;
+      break;
+    case BinaryConsts::V64x2SignSelect:
+      curr = allocator.alloc<SIMDTernary>();
+      curr->op = SignSelectVec64x2;
+      break;
     case BinaryConsts::F32x4QFMA:
       curr = allocator.alloc<SIMDTernary>();
       curr->op = QFMAF32x4;
@@ -4973,6 +5325,75 @@
   return true;
 }
 
+bool WasmBinaryBuilder::maybeVisitSIMDLoadStoreLane(Expression*& out,
+                                                    uint32_t code) {
+  SIMDLoadStoreLaneOp op;
+  size_t lanes;
+  switch (code) {
+    case BinaryConsts::V128Load8Lane:
+      op = LoadLaneVec8x16;
+      lanes = 16;
+      break;
+    case BinaryConsts::V128Load16Lane:
+      op = LoadLaneVec16x8;
+      lanes = 8;
+      break;
+    case BinaryConsts::V128Load32Lane:
+      op = LoadLaneVec32x4;
+      lanes = 4;
+      break;
+    case BinaryConsts::V128Load64Lane:
+      op = LoadLaneVec64x2;
+      lanes = 2;
+      break;
+    case BinaryConsts::V128Store8Lane:
+      op = StoreLaneVec8x16;
+      lanes = 16;
+      break;
+    case BinaryConsts::V128Store16Lane:
+      op = StoreLaneVec16x8;
+      lanes = 8;
+      break;
+    case BinaryConsts::V128Store32Lane:
+      op = StoreLaneVec32x4;
+      lanes = 4;
+      break;
+    case BinaryConsts::V128Store64Lane:
+      op = StoreLaneVec64x2;
+      lanes = 2;
+      break;
+    default:
+      return false;
+  }
+  auto* curr = allocator.alloc<SIMDLoadStoreLane>();
+  curr->op = op;
+  readMemoryAccess(curr->align, curr->offset);
+  curr->index = getLaneIndex(lanes);
+  curr->vec = popNonVoidExpression();
+  curr->ptr = popNonVoidExpression();
+  curr->finalize();
+  out = curr;
+  return true;
+}
+
+bool WasmBinaryBuilder::maybeVisitPrefetch(Expression*& out, uint32_t code) {
+  PrefetchOp op;
+  switch (code) {
+    case BinaryConsts::PrefetchT:
+      op = PrefetchTemporal;
+      break;
+    case BinaryConsts::PrefetchNT:
+      op = PrefetchNontemporal;
+      break;
+    default:
+      return false;
+  }
+  Address align, offset;
+  readMemoryAccess(align, offset);
+  out = Builder(wasm).makePrefetch(op, offset, align, popNonVoidExpression());
+  return true;
+}
+
 void WasmBinaryBuilder::visitSelect(Select* curr, uint8_t code) {
   BYN_TRACE("zz node: Select, code " << int32_t(code) << std::endl);
   if (code == BinaryConsts::SelectWithType) {
@@ -5051,7 +5472,10 @@
     throwError("ref.func: invalid call index");
   }
   functionRefs[index].push_back(curr); // we don't know function names yet
-  curr->finalize();
+  // To support typed function refs, we give the reference not just a general
+  // funcref, but a specific subtype with the actual signature.
+  // FIXME: for now, emit a nullable type here
+  curr->finalize(Type(HeapType(getSignatureByFunctionIndex(index)), Nullable));
 }
 
 void WasmBinaryBuilder::visitRefEq(RefEq* curr) {
@@ -5195,6 +5619,32 @@
   curr->finalize();
 }
 
+void WasmBinaryBuilder::visitCallRef(CallRef* curr) {
+  BYN_TRACE("zz node: CallRef\n");
+  curr->target = popNonVoidExpression();
+  auto type = curr->target->type;
+  if (type == Type::unreachable) {
+    // If our input is unreachable, then we cannot even find out how many inputs
+    // we have, and just set ourselves to unreachable as well.
+    curr->finalize(type);
+    return;
+  }
+  if (!type.isRef()) {
+    throwError("Non-ref type for a call_ref: " + type.toString());
+  }
+  auto heapType = type.getHeapType();
+  if (!heapType.isSignature()) {
+    throwError("Invalid reference type for a call_ref: " + type.toString());
+  }
+  auto sig = heapType.getSignature();
+  auto num = sig.params.size();
+  curr->operands.resize(num);
+  for (size_t i = 0; i < num; i++) {
+    curr->operands[num - i - 1] = popNonVoidExpression();
+  }
+  curr->finalize(sig.results);
+}
+
 bool WasmBinaryBuilder::maybeVisitI31New(Expression*& out, uint32_t code) {
   if (code != BinaryConsts::I31New) {
     return false;
@@ -5230,10 +5680,13 @@
   if (code != BinaryConsts::RefTest) {
     return false;
   }
-  auto* curr = allocator.alloc<RefTest>();
-  WASM_UNREACHABLE("TODO (gc): ref.test");
-  curr->finalize();
-  out = curr;
+  auto heapType1 = getHeapType();
+  auto heapType2 = getHeapType();
+  auto* ref = popNonVoidExpression();
+  validateHeapTypeUsingChild(ref, heapType1);
+  auto* rtt = popNonVoidExpression();
+  validateHeapTypeUsingChild(rtt, heapType2);
+  out = Builder(wasm).makeRefTest(ref, rtt);
   return true;
 }
 
@@ -5241,10 +5694,13 @@
   if (code != BinaryConsts::RefCast) {
     return false;
   }
-  auto* curr = allocator.alloc<RefCast>();
-  WASM_UNREACHABLE("TODO (gc): ref.cast");
-  curr->finalize();
-  out = curr;
+  auto heapType1 = getHeapType();
+  auto heapType2 = getHeapType();
+  auto* ref = popNonVoidExpression();
+  validateHeapTypeUsingChild(ref, heapType1);
+  auto* rtt = popNonVoidExpression();
+  validateHeapTypeUsingChild(rtt, heapType2);
+  out = Builder(wasm).makeRefCast(ref, rtt);
   return true;
 }
 
@@ -5252,10 +5708,14 @@
   if (code != BinaryConsts::BrOnCast) {
     return false;
   }
-  auto* curr = allocator.alloc<BrOnCast>();
-  WASM_UNREACHABLE("TODO (gc): br_on_cast");
-  curr->finalize();
-  out = curr;
+  auto name = getBreakTarget(getU32LEB()).name;
+  auto heapType1 = getHeapType();
+  auto heapType2 = getHeapType();
+  auto* ref = popNonVoidExpression();
+  validateHeapTypeUsingChild(ref, heapType1);
+  auto* rtt = popNonVoidExpression();
+  validateHeapTypeUsingChild(rtt, heapType2);
+  out = Builder(wasm).makeBrOnCast(name, heapType2, ref, rtt);
   return true;
 }
 
@@ -5263,10 +5723,8 @@
   if (code != BinaryConsts::RttCanon) {
     return false;
   }
-  auto* curr = allocator.alloc<RttCanon>();
-  WASM_UNREACHABLE("TODO (gc): rtt.canon");
-  curr->finalize();
-  out = curr;
+  auto heapType = getHeapType();
+  out = Builder(wasm).makeRttCanon(heapType);
   return true;
 }
 
@@ -5274,30 +5732,31 @@
   if (code != BinaryConsts::RttSub) {
     return false;
   }
-  auto* curr = allocator.alloc<RttSub>();
-  WASM_UNREACHABLE("TODO (gc): rtt.sub");
-  curr->finalize();
-  out = curr;
+  // FIXME: the binary format may also have an extra heap type and index that
+  //        are not needed
+  auto heapType = getHeapType();
+  auto* parent = popNonVoidExpression();
+  out = Builder(wasm).makeRttSub(heapType, parent);
   return true;
 }
 
 bool WasmBinaryBuilder::maybeVisitStructNew(Expression*& out, uint32_t code) {
-  StructNew* curr;
-  switch (code) {
-    case BinaryConsts::StructNewWithRtt:
-      curr = allocator.alloc<StructNew>();
-      // ...
-      break;
-    case BinaryConsts::StructNewDefaultWithRtt:
-      curr = allocator.alloc<StructNew>();
-      // ...
-      break;
-    default:
-      return false;
+  if (code != BinaryConsts::StructNewWithRtt &&
+      code != BinaryConsts::StructNewDefaultWithRtt) {
+    return false;
   }
-  WASM_UNREACHABLE("TODO (gc): struct.new");
-  curr->finalize();
-  out = curr;
+  auto heapType = getHeapType();
+  auto* rtt = popNonVoidExpression();
+  validateHeapTypeUsingChild(rtt, heapType);
+  std::vector<Expression*> operands;
+  if (code == BinaryConsts::StructNewWithRtt) {
+    auto numOperands = heapType.getStruct().fields.size();
+    operands.resize(numOperands);
+    for (Index i = 0; i < numOperands; i++) {
+      operands[numOperands - i - 1] = popNonVoidExpression();
+    }
+  }
+  out = Builder(wasm).makeStructNew(rtt, operands);
   return true;
 }
 
@@ -5306,20 +5765,22 @@
   switch (code) {
     case BinaryConsts::StructGet:
       curr = allocator.alloc<StructGet>();
-      // ...
       break;
     case BinaryConsts::StructGetS:
       curr = allocator.alloc<StructGet>();
-      // ...
+      curr->signed_ = true;
       break;
     case BinaryConsts::StructGetU:
       curr = allocator.alloc<StructGet>();
-      // ...
+      curr->signed_ = false;
       break;
     default:
       return false;
   }
-  WASM_UNREACHABLE("TODO (gc): struct.get");
+  auto heapType = getHeapType();
+  curr->index = getU32LEB();
+  curr->ref = popNonVoidExpression();
+  validateHeapTypeUsingChild(curr->ref, heapType);
   curr->finalize();
   out = curr;
   return true;
@@ -5330,53 +5791,50 @@
     return false;
   }
   auto* curr = allocator.alloc<StructSet>();
-  WASM_UNREACHABLE("TODO (gc): struct.set");
+  auto heapType = getHeapType();
+  curr->index = getU32LEB();
+  curr->ref = popNonVoidExpression();
+  validateHeapTypeUsingChild(curr->ref, heapType);
+  curr->value = popNonVoidExpression();
   curr->finalize();
   out = curr;
   return true;
 }
 
 bool WasmBinaryBuilder::maybeVisitArrayNew(Expression*& out, uint32_t code) {
-  ArrayNew* curr;
-  switch (code) {
-    case BinaryConsts::ArrayNewWithRtt:
-      curr = allocator.alloc<ArrayNew>();
-      // ...
-      break;
-    case BinaryConsts::ArrayNewDefaultWithRtt:
-      curr = allocator.alloc<ArrayNew>();
-      // ...
-      break;
-    default:
-      return false;
+  if (code != BinaryConsts::ArrayNewWithRtt &&
+      code != BinaryConsts::ArrayNewDefaultWithRtt) {
+    return false;
   }
-  WASM_UNREACHABLE("TODO (gc): array.new");
-  curr->finalize();
-  out = curr;
+  auto heapType = getHeapType();
+  auto* rtt = popNonVoidExpression();
+  validateHeapTypeUsingChild(rtt, heapType);
+  auto* size = popNonVoidExpression();
+  Expression* init = nullptr;
+  if (code == BinaryConsts::ArrayNewWithRtt) {
+    init = popNonVoidExpression();
+  }
+  out = Builder(wasm).makeArrayNew(rtt, size, init);
   return true;
 }
 
 bool WasmBinaryBuilder::maybeVisitArrayGet(Expression*& out, uint32_t code) {
-  ArrayGet* curr;
+  bool signed_ = false;
   switch (code) {
     case BinaryConsts::ArrayGet:
-      curr = allocator.alloc<ArrayGet>();
-      // ...
+    case BinaryConsts::ArrayGetU:
       break;
     case BinaryConsts::ArrayGetS:
-      curr = allocator.alloc<ArrayGet>();
-      // ...
-      break;
-    case BinaryConsts::ArrayGetU:
-      curr = allocator.alloc<ArrayGet>();
-      // ...
+      signed_ = true;
       break;
     default:
       return false;
   }
-  WASM_UNREACHABLE("TODO (gc): array.get");
-  curr->finalize();
-  out = curr;
+  auto heapType = getHeapType();
+  auto* ref = popNonVoidExpression();
+  validateHeapTypeUsingChild(ref, heapType);
+  auto* index = popNonVoidExpression();
+  out = Builder(wasm).makeArrayGet(ref, index, signed_);
   return true;
 }
 
@@ -5384,10 +5842,12 @@
   if (code != BinaryConsts::ArraySet) {
     return false;
   }
-  auto* curr = allocator.alloc<ArraySet>();
-  WASM_UNREACHABLE("TODO (gc): array.set");
-  curr->finalize();
-  out = curr;
+  auto heapType = getHeapType();
+  auto* ref = popNonVoidExpression();
+  validateHeapTypeUsingChild(ref, heapType);
+  auto* index = popNonVoidExpression();
+  auto* value = popNonVoidExpression();
+  out = Builder(wasm).makeArraySet(ref, index, value);
   return true;
 }
 
@@ -5395,15 +5855,27 @@
   if (code != BinaryConsts::ArrayLen) {
     return false;
   }
-  auto* curr = allocator.alloc<ArrayLen>();
-  WASM_UNREACHABLE("TODO (gc): array.len");
-  curr->finalize();
-  out = curr;
+  auto heapType = getHeapType();
+  auto* ref = popNonVoidExpression();
+  validateHeapTypeUsingChild(ref, heapType);
+  out = Builder(wasm).makeArrayLen(ref);
   return true;
 }
 
 void WasmBinaryBuilder::throwError(std::string text) {
   throw ParseException(text, 0, pos);
+}
+
+void WasmBinaryBuilder::validateHeapTypeUsingChild(Expression* child,
+                                                   HeapType heapType) {
+  if (child->type == Type::unreachable) {
+    return;
+  }
+  if ((!child->type.isRef() && !child->type.isRtt()) ||
+      child->type.getHeapType() != heapType) {
+    throwError("bad heap type: expected " + heapType.toString() +
+               " but found " + child->type.toString());
+  }
 }
 
 } // namespace wasm
diff --git a/binaryen/src/wasm/wasm-debug.cpp b/binaryen/src/wasm/wasm-debug.cpp
--- a/binaryen/src/wasm/wasm-debug.cpp
+++ b/binaryen/src/wasm/wasm-debug.cpp
@@ -635,6 +635,17 @@
   }
 };
 
+// A tombstone value is a value that is placed where something used to exist,
+// but no longer does, like a reference to a function that was DCE'd out during
+// linking. In theory the value can be any invalid location, and tools will
+// basically ignore it.
+// Earlier LLVM used to use 0 there, and newer versions use -1 or -2 depending
+// on the DWARF section. For now, support them all, but TODO stop supporting 0,
+// as there are apparently some possible corner cases where 0 is a valid value.
+static bool isTombstone(uint32_t x) {
+  return x == 0 || x == uint32_t(-1) || x == uint32_t(-2);
+}
+
 // Update debug lines, and update the locationUpdater with debug line offset
 // changes so we can update offsets into the debug line section.
 static void updateDebugLines(llvm::DWARFYAML::Data& data,
@@ -656,7 +667,7 @@
         omittingRange = false;
       }
       if (state.update(opcode, table)) {
-        if (state.addr == 0) {
+        if (isTombstone(state.addr)) {
           omittingRange = true;
         }
         if (omittingRange) {
@@ -680,6 +691,8 @@
           newAddr = locationUpdater.getNewFuncStart(oldAddr);
         } else if (locationUpdater.hasOldDelimiter(oldAddr)) {
           newAddr = locationUpdater.getNewDelimiter(oldAddr);
+        } else if (locationUpdater.hasOldExprEnd(oldAddr)) {
+          newAddr = locationUpdater.getNewExprEnd(oldAddr);
         }
         if (newAddr && state.needToEmit()) {
           // LLVM sometimes emits the same address more than once. We should
@@ -851,7 +864,8 @@
 
 static void updateCompileUnits(const BinaryenDWARFInfo& info,
                                llvm::DWARFYAML::Data& yaml,
-                               LocationUpdater& locationUpdater) {
+                               LocationUpdater& locationUpdater,
+                               bool is64) {
   // The context has the high-level information we need, and the YAML is where
   // we write changes. First, iterate over the compile units.
   size_t compileUnitIndex = 0;
@@ -860,6 +874,13 @@
     yaml.CompileUnits,
     [&](const std::unique_ptr<llvm::DWARFUnit>& CU,
         llvm::DWARFYAML::Unit& yamlUnit) {
+      // Our Memory64Lowering pass may change the "architecture" of the DWARF
+      // data. AddrSize will cause all DW_AT_low_pc to be written as 32/64-bit.
+      auto NewAddrSize = is64 ? 8 : 4;
+      if (NewAddrSize != yamlUnit.AddrSize) {
+        yamlUnit.AddrSize = NewAddrSize;
+        yamlUnit.AddrSizeChanged = true;
+      }
       // Process the DIEs in each compile unit.
       iterContextAndYAML(
         CU->dies(),
@@ -891,14 +912,14 @@
     // If this is an end marker (0, 0), or an invalid range (0, x) or (x, 0)
     // then just emit it as it is - either to mark the end, or to mark an
     // invalid entry.
-    if (oldStart == 0 || oldEnd == 0) {
+    if (isTombstone(oldStart) || isTombstone(oldEnd)) {
       newStart = oldStart;
       newEnd = oldEnd;
     } else {
       // This was a valid entry; update it.
       newStart = locationUpdater.getNewStart(oldStart);
       newEnd = locationUpdater.getNewEnd(oldEnd);
-      if (newStart == 0 || newEnd == 0) {
+      if (isTombstone(newStart) || isTombstone(newEnd)) {
         // This part of the range no longer has a mapping, so we must skip it.
         // Don't use (0, 0) as that would be an end marker; emit something
         // invalid for the debugger to ignore.
@@ -925,7 +946,7 @@
 }
 
 static bool isEndMarkerLoc(const llvm::DWARFYAML::Loc& loc) {
-  return loc.Start == 0 && loc.End == 0;
+  return isTombstone(loc.Start) && isTombstone(loc.End);
 }
 
 // Update the .debug_loc section.
@@ -1037,7 +1058,7 @@
 
   updateDebugLines(data, locationUpdater);
 
-  updateCompileUnits(info, data, locationUpdater);
+  updateCompileUnits(info, data, locationUpdater, wasm.memory.is64());
 
   updateRanges(data, locationUpdater);
 
diff --git a/binaryen/src/wasm/wasm-emscripten.cpp b/binaryen/src/wasm/wasm-emscripten.cpp
--- a/binaryen/src/wasm/wasm-emscripten.cpp
+++ b/binaryen/src/wasm/wasm-emscripten.cpp
@@ -38,7 +38,6 @@
 cashew::IString EM_JS_PREFIX("__em_js__");
 
 static Name STACK_INIT("stack$init");
-static Name POST_INSTANTIATE("__post_instantiate");
 
 void addExportedFunction(Module& wasm, Function* function) {
   wasm.addFunction(function);
@@ -75,73 +74,6 @@
   return nullptr;
 }
 
-// For emscripten SIDE_MODULE we generate a single exported function called
-// __post_instantiate which calls two functions:
-//
-// - __assign_got_enties
-// - __wasm_call_ctors
-//
-// The former is function we generate here which calls imported g$XXX functions
-// order to assign values to any globals imported from GOT.func or GOT.mem.
-// These globals hold address of functions and globals respectively.
-//
-// The later is the constructor function generaed by lld which performs any
-// fixups on the memory section and calls static constructors.
-void EmscriptenGlueGenerator::generatePostInstantiateFunction() {
-  BYN_TRACE("generatePostInstantiateFunction\n");
-  Builder builder(wasm);
-  Function* post_instantiate = builder.makeFunction(
-    POST_INSTANTIATE, std::vector<NameType>{}, Type::none, {});
-  wasm.addFunction(post_instantiate);
-
-  if (Function* F = wasm.getFunctionOrNull(ASSIGN_GOT_ENTRIES)) {
-    // call __assign_got_enties from post_instantiate
-    Expression* call = builder.makeCall(F->name, {}, Type::none);
-    post_instantiate->body = builder.blockify(post_instantiate->body, call);
-  }
-
-  // The names of standard imports/exports used by lld doesn't quite match that
-  // expected by emscripten.
-  // TODO(sbc): Unify these
-  if (auto* e = wasm.getExportOrNull(WASM_CALL_CTORS)) {
-    Expression* call = builder.makeCall(e->value, {}, Type::none);
-    post_instantiate->body = builder.blockify(post_instantiate->body, call);
-    wasm.removeExport(WASM_CALL_CTORS);
-  }
-
-  auto* ex = new Export();
-  ex->value = post_instantiate->name;
-  ex->name = POST_INSTANTIATE;
-  ex->kind = ExternalKind::Function;
-  wasm.addExport(ex);
-}
-
-// lld can sometimes produce a build with an imported mutable __stack_pointer
-// (i.e.  when linking with -fpie).  This method internalizes the
-// __stack_pointer and initializes it from an immutable global instead.
-// For -shared builds we instead call replaceStackPointerGlobal.
-void EmscriptenGlueGenerator::internalizeStackPointerGlobal() {
-  Global* stackPointer = getStackPointerGlobal(wasm);
-  if (!stackPointer || !stackPointer->imported() || !stackPointer->mutable_) {
-    return;
-  }
-
-  Name internalName = stackPointer->name;
-  Name externalName = internalName.c_str() + std::string("_import");
-
-  // Rename the imported global, and make it immutable
-  stackPointer->name = externalName;
-  stackPointer->mutable_ = false;
-  wasm.updateMaps();
-
-  // Create a new global with the old name that is not imported.
-  Builder builder(wasm);
-  auto* init = builder.makeGlobalGet(externalName, stackPointer->type);
-  auto* sp = builder.makeGlobal(
-    internalName, stackPointer->type, init, Builder::Mutable);
-  wasm.addGlobal(sp);
-}
-
 const Address UNKNOWN_OFFSET(uint32_t(-1));
 
 std::vector<Address> getSegmentOffsets(Module& wasm) {
@@ -153,9 +85,19 @@
       OffsetSearcher(std::unordered_map<unsigned, Address>& offsets)
         : offsets(offsets) {}
       void visitMemoryInit(MemoryInit* curr) {
+        // The desitination of the memory.init is either a constant
+        // or the result of an addition with __memory_base in the
+        // case of PIC code.
         auto* dest = curr->dest->dynCast<Const>();
         if (!dest) {
-          return;
+          auto* add = curr->dest->dynCast<Binary>();
+          if (!add) {
+            return;
+          }
+          dest = add->left->dynCast<Const>();
+          if (!dest) {
+            return;
+          }
         }
         auto it = offsets.find(curr->segment);
         if (it != offsets.end()) {
@@ -235,12 +177,10 @@
 
 std::string codeForConstAddr(Module& wasm,
                              std::vector<Address> const& segmentOffsets,
-                             int32_t address) {
+                             int64_t address) {
   const char* str = stringAtAddr(wasm, segmentOffsets, address);
   if (!str) {
-    // If we can't find the segment corresponding with the address, then we
-    // omitted the segment and the address points to an empty string.
-    return escape("");
+    Fatal() << "unable to find data for ASM/EM_JS const at: " << address;
   }
   return escape(str);
 }
@@ -292,10 +232,9 @@
   void process();
 
 private:
-  void createAsmConst(uint32_t id, std::string code, Signature sig, Name name);
+  void createAsmConst(uint64_t id, std::string code, Signature sig, Name name);
   Signature asmConstSig(Signature baseSig);
   Name nameForImportWithSig(Signature sig, Proxying proxy);
-  void queueImport(Name importName, Signature baseSig);
   void addImports();
   Proxying proxyType(Name name);
 
@@ -352,7 +291,7 @@
     }
 
     if (auto* bin = arg->dynCast<Binary>()) {
-      if (bin->op == AddInt32) {
+      if (bin->op == AddInt32 || bin->op == AddInt64) {
         // In the dynamic linking case the address of the string constant
         // is the result of adding its offset to __memory_base.
         // In this case are only looking for the offset from __memory_base
@@ -362,12 +301,21 @@
       }
     }
 
+    if (auto* unary = arg->dynCast<Unary>()) {
+      if (unary->op == WrapInt64) {
+        // This cast may be inserted around the string constant in the
+        // Memory64Lowering pass.
+        arg = unary->value;
+        continue;
+      }
+    }
+
     Fatal() << "Unexpected arg0 type (" << getExpressionName(arg)
             << ") in call to: " << importName;
   }
 
   auto* value = arg->cast<Const>();
-  int32_t address = value->value.geti32();
+  int64_t address = value->value.getInteger();
   auto code = codeForConstAddr(wasm, segmentOffsets, address);
   createAsmConst(address, code, sig, importName);
 }
@@ -389,7 +337,7 @@
   addImports();
 }
 
-void AsmConstWalker::createAsmConst(uint32_t id,
+void AsmConstWalker::createAsmConst(uint64_t id,
                                     std::string code,
                                     Signature sig,
                                     Name name) {
@@ -410,21 +358,6 @@
     baseSig.results);
 }
 
-Name AsmConstWalker::nameForImportWithSig(Signature sig, Proxying proxy) {
-  std::string fixedTarget = EM_ASM_PREFIX.str + std::string("_") +
-                            proxyingSuffix(proxy) +
-                            getSig(sig.results, sig.params);
-  return Name(fixedTarget.c_str());
-}
-
-void AsmConstWalker::queueImport(Name importName, Signature baseSig) {
-  auto import = new Function;
-  import->name = import->base = importName;
-  import->module = ENV;
-  import->sig = baseSig;
-  queuedImports.push_back(std::unique_ptr<Function>(import));
-}
-
 void AsmConstWalker::addImports() {
   for (auto& import : queuedImports) {
     wasm.addFunction(import.release());
@@ -464,7 +397,7 @@
       Fatal() << "Unexpected generated __em_js__ function body: " << curr->name;
     }
     auto* addrConst = consts.list[0];
-    int32_t address = addrConst->value.geti32();
+    int64_t address = addrConst->value.getInteger();
     auto code = codeForConstAddr(wasm, segmentOffsets, address);
     codeByName[funcName] = code;
   }
@@ -501,8 +434,8 @@
   o << "]";
 }
 
-std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
-  Address staticBump, std::vector<Name> const& initializerFunctions) {
+std::string
+EmscriptenGlueGenerator::generateEmscriptenMetadata(Name initializer) {
   bool commaFirst;
   auto nextElement = [&commaFirst]() {
     if (commaFirst) {
@@ -547,16 +480,11 @@
     meta << "\n  },\n";
   }
 
-  meta << "  \"staticBump\": " << staticBump << ",\n";
   meta << "  \"tableSize\": " << wasm.table.initial.addr << ",\n";
 
-  if (!initializerFunctions.empty()) {
+  if (initializer.is()) {
     meta << "  \"initializers\": [";
-    commaFirst = true;
-    for (const auto& func : initializerFunctions) {
-      meta << nextElement();
-      meta << "\"" << func.c_str() << "\"";
-    }
+    meta << "\n    \"" << initializer.c_str() << "\"";
     meta << "\n  ],\n";
   }
 
diff --git a/binaryen/src/wasm/wasm-io.cpp b/binaryen/src/wasm/wasm-io.cpp
--- a/binaryen/src/wasm/wasm-io.cpp
+++ b/binaryen/src/wasm/wasm-io.cpp
@@ -121,7 +121,7 @@
 #define DEBUG_TYPE "writer"
 
 void ModuleWriter::writeText(Module& wasm, Output& output) {
-  WasmPrinter::printModule(&wasm, output.getStream());
+  output.getStream() << wasm;
 }
 
 void ModuleWriter::writeText(Module& wasm, std::string filename) {
diff --git a/binaryen/src/wasm/wasm-s-parser.cpp b/binaryen/src/wasm/wasm-s-parser.cpp
--- a/binaryen/src/wasm/wasm-s-parser.cpp
+++ b/binaryen/src/wasm/wasm-s-parser.cpp
@@ -20,11 +20,11 @@
 #include <cmath>
 #include <limits>
 
-#include "asm_v_wasm.h"
-#include "asmjs/shared-constants.h"
 #include "ir/branch-utils.h"
 #include "shared-constants.h"
+#include "support/string.h"
 #include "wasm-binary.h"
+#include "wasm-builder.h"
 
 #define abort_on(str)                                                          \
   { throw ParseException(std::string("abort_on ") + str); }
@@ -50,6 +50,9 @@
 
 namespace wasm {
 
+static Name STRUCT("struct"), FIELD("field"), ARRAY("array"), I8("i8"),
+  I16("i16"), RTT("rtt");
+
 static Address getAddress(const Element* s) { return atoll(s->c_str()); }
 
 static void
@@ -63,6 +66,10 @@
   return s.isList() && s.size() > 0 && s[0]->isStr() && s[0]->str() == str;
 }
 
+static bool elementStartsWith(Element* s, IString str) {
+  return elementStartsWith(*s, str);
+}
+
 Element::List& Element::list() {
   if (!isList()) {
     throw ParseException("expected list", line, col);
@@ -451,25 +458,6 @@
   }
 }
 
-Signature SExpressionWasmBuilder::getFunctionSignature(Element& s) {
-  if (s.dollared()) {
-    auto it = signatureIndices.find(s.str().str);
-    if (it == signatureIndices.end()) {
-      throw ParseException(
-        "unknown function type in getFunctionSignature", s.line, s.col);
-    }
-    return signatures[it->second];
-  } else {
-    // index
-    size_t offset = atoi(s.str().c_str());
-    if (offset >= signatures.size()) {
-      throw ParseException(
-        "unknown function type in getFunctionSignature", s.line, s.col);
-    }
-    return signatures[offset];
-  }
-}
-
 Name SExpressionWasmBuilder::getGlobalName(Element& s) {
   if (s.dollared()) {
     return s.str();
@@ -538,14 +526,10 @@
     }
     localIndex++;
     Type type;
-    if (s[i]->isStr()) {
-      type = stringToType(s[i]->str());
-    } else {
-      if (elementStartsWith(s, PARAM)) {
-        throw ParseException(
-          "params may not have tuple types", s[i]->line, s[i]->col);
-      }
-      type = elementToType(*s[i]);
+    type = elementToType(*s[i]);
+    if (elementStartsWith(s, PARAM) && type.isTuple()) {
+      throw ParseException(
+        "params may not have tuple types", s[i]->line, s[i]->col);
     }
     namedParams.emplace_back(name, type);
   }
@@ -557,7 +541,7 @@
   assert(elementStartsWith(s, RESULT));
   std::vector<Type> types;
   for (size_t i = 1; i < s.size(); i++) {
-    types.push_back(stringToType(s[i]->str()));
+    types.push_back(elementToType(*s[i]));
   }
   return types;
 }
@@ -570,7 +554,11 @@
   if (s.size() != 2) {
     throw ParseException("invalid type reference", s.line, s.col);
   }
-  return getFunctionSignature(*s[1]);
+  auto heapType = parseHeapType(*s[1]);
+  if (!heapType.isSignature()) {
+    throw ParseException("expected signature type", s.line, s.col);
+  }
+  return heapType.getSignature();
 }
 
 // Prases typeuse, a reference to a type definition. It is in the form of either
@@ -632,9 +620,9 @@
   }
 
   // Add implicitly defined type to global list so it has an index
-  if (std::find(signatures.begin(), signatures.end(), functionSignature) ==
-      signatures.end()) {
-    signatures.push_back(functionSignature);
+  auto heapType = HeapType(functionSignature);
+  if (std::find(types.begin(), types.end(), heapType) == types.end()) {
+    types.push_back(heapType);
   }
 
   // If only (type) is specified, populate `namedParams`
@@ -675,7 +663,7 @@
   functionCounter++;
   Signature sig;
   parseTypeUse(s, i, sig);
-  functionTypes[name] = sig.results;
+  functionSignatures[name] = sig;
 }
 
 size_t SExpressionWasmBuilder::parseFunctionNames(Element& s,
@@ -714,6 +702,7 @@
 
   Name name, exportName;
   size_t i = parseFunctionNames(s, name, exportName);
+  bool hasExplicitName = name.is();
   if (!preParseImport) {
     if (!name.is()) {
       // unnamed, use an index
@@ -762,11 +751,11 @@
       throw ParseException("!preParseImport in func", s.line, s.col);
     }
     auto im = make_unique<Function>();
-    im->name = name;
+    im->setName(name, hasExplicitName);
     im->module = importModule;
     im->base = importBase;
     im->sig = sig;
-    functionTypes[name] = sig.results;
+    functionSignatures[name] = sig;
     if (wasm.getFunctionOrNull(im->name)) {
       throw ParseException("duplicate import", s.line, s.col);
     }
@@ -879,7 +868,8 @@
     return Type::eqref;
   }
   if (strncmp(str, "i31ref", 6) == 0 && (prefix || str[6] == 0)) {
-    return Type::i31ref;
+    // FIXME: for now, force all inputs to be nullable
+    return Type(HeapType::BasicHeapType::i31, Nullable);
   }
   if (allowError) {
     return Type::none;
@@ -891,32 +881,32 @@
                                                   bool prefix) {
   if (str[0] == 'a') {
     if (str[1] == 'n' && str[2] == 'y' && (prefix || str[3] == 0)) {
-      return HeapType::AnyKind;
+      return HeapType::any;
     }
   }
   if (str[0] == 'e') {
     if (str[1] == 'q' && (prefix || str[2] == 0)) {
-      return HeapType::EqKind;
+      return HeapType::eq;
     }
     if (str[1] == 'x') {
       if (str[2] == 'n' && (prefix || str[3] == 0)) {
-        return HeapType::ExnKind;
+        return HeapType::exn;
       }
       if (str[2] == 't' && str[3] == 'e' && str[4] == 'r' && str[5] == 'n' &&
           (prefix || str[6] == 0)) {
-        return HeapType::ExternKind;
+        return HeapType::ext;
       }
     }
   }
   if (str[0] == 'i') {
     if (str[1] == '3' && str[2] == '1' && (prefix || str[3] == 0)) {
-      return HeapType::I31Kind;
+      return HeapType::i31;
     }
   }
   if (str[0] == 'f') {
     if (str[1] == 'u' && str[2] == 'n' && str[3] == 'c' &&
         (prefix || str[4] == 0)) {
-      return HeapType::FuncKind;
+      return HeapType::func;
     }
   }
   throw ParseException(std::string("invalid wasm heap type: ") + str);
@@ -924,12 +914,50 @@
 
 Type SExpressionWasmBuilder::elementToType(Element& s) {
   if (s.isStr()) {
-    return stringToType(s.str(), false, false);
+    return stringToType(s.str());
   }
-  auto& tuple = s.list();
+  auto& list = s.list();
+  auto size = list.size();
+  if (elementStartsWith(s, REF)) {
+    // It's a reference. It should be in the form
+    //   (ref $name)
+    // or
+    //   (ref null $name)
+    // and also $name can be the expanded structure of the type and not a name,
+    // so something like (ref (func (result i32))), etc.
+    if (size != 2 && size != 3) {
+      throw ParseException(
+        std::string("invalid reference type size"), s.line, s.col);
+    }
+    if (size == 3 && *list[1] != NULL_) {
+      throw ParseException(
+        std::string("invalid reference type qualifier"), s.line, s.col);
+    }
+    // FIXME: for now, force all inputs to be nullable
+    Nullability nullable = Nullable;
+    size_t i = 1;
+    if (size == 3) {
+      nullable = Nullable;
+      i++;
+    }
+    return Type(parseHeapType(*s[i]), nullable);
+  }
+  if (elementStartsWith(s, RTT)) {
+    // It's an RTT, something like (rtt N $typename) or just (rtt $typename)
+    // if there is no depth.
+    if (s[1]->dollared()) {
+      auto heapType = parseHeapType(*s[1]);
+      return Type(Rtt(heapType));
+    } else {
+      auto depth = atoi(s[1]->str().c_str());
+      auto heapType = parseHeapType(*s[2]);
+      return Type(Rtt(depth, heapType));
+    }
+  }
+  // It's a tuple.
   std::vector<Type> types;
   for (size_t i = 0; i < s.size(); ++i) {
-    types.push_back(stringToType(tuple[i]->str()));
+    types.push_back(elementToType(*list[i]));
   }
   return Type(types);
 }
@@ -1299,8 +1327,12 @@
   size_t i = 1;
   offset = 0;
   align = fallbackAlign;
+  // Parse "align=X" and "offset=X" arguments, bailing out on anything else.
   while (!s[i]->isList()) {
     const char* str = s[i]->c_str();
+    if (strncmp(str, "align", 5) != 0 && strncmp(str, "offset", 6) != 0) {
+      return i;
+    }
     const char* eq = strchr(str, '=');
     if (!eq) {
       throw ParseException(
@@ -1404,17 +1436,17 @@
   ret->type = type;
   ret->bytes = bytes;
   if (!strncmp(extra, "add", 3)) {
-    ret->op = Add;
+    ret->op = RMWAdd;
   } else if (!strncmp(extra, "and", 3)) {
-    ret->op = And;
+    ret->op = RMWAnd;
   } else if (!strncmp(extra, "or", 2)) {
-    ret->op = Or;
+    ret->op = RMWOr;
   } else if (!strncmp(extra, "sub", 3)) {
-    ret->op = Sub;
+    ret->op = RMWSub;
   } else if (!strncmp(extra, "xor", 3)) {
-    ret->op = Xor;
+    ret->op = RMWXor;
   } else if (!strncmp(extra, "xchg", 4)) {
-    ret->op = Xchg;
+    ret->op = RMWXchg;
   } else {
     throw ParseException("bad atomic rmw operator", s.line, s.col);
   }
@@ -1460,11 +1492,12 @@
   } else if (type == Type::i64) {
     expectedAlign = 8;
   } else {
-    WASM_UNREACHABLE("Invalid prefix for atomic.wait");
+    WASM_UNREACHABLE("Invalid prefix for memory.atomic.wait");
   }
   size_t i = parseMemAttributes(s, ret->offset, align, expectedAlign);
   if (align != expectedAlign) {
-    throw ParseException("Align of atomic.wait must match size", s.line, s.col);
+    throw ParseException(
+      "Align of memory.atomic.wait must match size", s.line, s.col);
   }
   ret->ptr = parseExpression(s[i]);
   ret->expected = parseExpression(s[i + 1]);
@@ -1479,7 +1512,8 @@
   Address align;
   size_t i = parseMemAttributes(s, ret->offset, align, 4);
   if (align != 4) {
-    throw ParseException("Align of atomic.notify must be 4", s.line, s.col);
+    throw ParseException(
+      "Align of memory.atomic.notify must be 4", s.line, s.col);
   }
   ret->ptr = parseExpression(s[i]);
   ret->notifyCount = parseExpression(s[i + 1]);
@@ -1591,6 +1625,51 @@
   return ret;
 }
 
+Expression*
+SExpressionWasmBuilder::makeSIMDLoadStoreLane(Element& s,
+                                              SIMDLoadStoreLaneOp op) {
+  auto* ret = allocator.alloc<SIMDLoadStoreLane>();
+  ret->op = op;
+  Address defaultAlign;
+  size_t lanes;
+  switch (op) {
+    case LoadLaneVec8x16:
+    case StoreLaneVec8x16:
+      defaultAlign = 1;
+      lanes = 16;
+      break;
+    case LoadLaneVec16x8:
+    case StoreLaneVec16x8:
+      defaultAlign = 2;
+      lanes = 8;
+      break;
+    case LoadLaneVec32x4:
+    case StoreLaneVec32x4:
+      defaultAlign = 4;
+      lanes = 4;
+      break;
+    case LoadLaneVec64x2:
+    case StoreLaneVec64x2:
+      defaultAlign = 8;
+      lanes = 2;
+      break;
+    default:
+      WASM_UNREACHABLE("Unexpected SIMDLoadStoreLane op");
+  }
+  size_t i = parseMemAttributes(s, ret->offset, ret->align, defaultAlign);
+  ret->index = parseLaneIndex(s[i++], lanes);
+  ret->ptr = parseExpression(s[i++]);
+  ret->vec = parseExpression(s[i]);
+  ret->finalize();
+  return ret;
+}
+
+Expression* SExpressionWasmBuilder::makePrefetch(Element& s, PrefetchOp op) {
+  Address offset, align;
+  size_t i = parseMemAttributes(s, offset, align, /*defaultAlign*/ 1);
+  return Builder(wasm).makePrefetch(op, offset, align, parseExpression(s[i]));
+}
+
 Expression* SExpressionWasmBuilder::makeMemoryInit(Element& s) {
   auto ret = allocator.alloc<MemoryInit>();
   ret->segment = atoi(s[1]->str().c_str());
@@ -1729,7 +1808,7 @@
   auto target = getFunctionName(*s[1]);
   auto ret = allocator.alloc<Call>();
   ret->target = target;
-  ret->type = functionTypes[ret->target];
+  ret->type = functionSignatures[ret->target].results;
   parseCallOperands(s, 2, s.size(), ret);
   ret->isReturn = isReturn;
   ret->finalize();
@@ -1829,9 +1908,15 @@
   if (s.size() != 2) {
     throw ParseException("invalid heap type reference", s.line, s.col);
   }
-  auto heapType = stringToHeapType(s[1]->str());
   auto ret = allocator.alloc<RefNull>();
-  ret->finalize(heapType);
+  // The heap type may be just "func", that is, the whole thing is just
+  // (ref.null func), or it may be the name of a defined type, such as
+  // (ref.null $struct.FOO)
+  if (s[1]->dollared()) {
+    ret->finalize(parseHeapType(*s[1]));
+  } else {
+    ret->finalize(stringToHeapType(s[1]->str()));
+  }
   return ret;
 }
 
@@ -1846,7 +1931,9 @@
   auto func = getFunctionName(*s[1]);
   auto ret = allocator.alloc<RefFunc>();
   ret->func = func;
-  ret->finalize();
+  // To support typed function refs, we give the reference not just a general
+  // funcref, but a specific subtype with the actual signature.
+  ret->finalize(Type(HeapType(functionSignatures[func]), Nullable));
   return ret;
 }
 
@@ -1979,6 +2066,24 @@
   return ret;
 }
 
+Expression* SExpressionWasmBuilder::makeCallRef(Element& s, bool isReturn) {
+  auto ret = allocator.alloc<CallRef>();
+  parseCallOperands(s, 1, s.size() - 1, ret);
+  ret->target = parseExpression(s[s.size() - 1]);
+  ret->isReturn = isReturn;
+  if (!ret->target->type.isRef()) {
+    throw ParseException("Non-reference type for a call_ref", s.line, s.col);
+  }
+  auto heapType = ret->target->type.getHeapType();
+  if (!heapType.isSignature()) {
+    throw ParseException(
+      "Invalid reference type for a call_ref", s.line, s.col);
+  }
+  auto sig = heapType.getSignature();
+  ret->finalize(sig.results);
+  return ret;
+}
+
 Expression* SExpressionWasmBuilder::makeI31New(Element& s) {
   auto ret = allocator.alloc<I31New>();
   ret->value = parseExpression(s[1]);
@@ -1995,101 +2100,125 @@
 }
 
 Expression* SExpressionWasmBuilder::makeRefTest(Element& s) {
-  auto ret = allocator.alloc<RefTest>();
-  WASM_UNREACHABLE("TODO (gc): ref.test");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto* ref = parseExpression(*s[2]);
+  auto* rtt = parseExpression(*s[3]);
+  validateHeapTypeUsingChild(rtt, heapType, s);
+  return Builder(wasm).makeRefTest(ref, rtt);
 }
 
 Expression* SExpressionWasmBuilder::makeRefCast(Element& s) {
-  auto ret = allocator.alloc<RefCast>();
-  WASM_UNREACHABLE("TODO (gc): ref.cast");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto* ref = parseExpression(*s[2]);
+  auto* rtt = parseExpression(*s[3]);
+  validateHeapTypeUsingChild(rtt, heapType, s);
+  return Builder(wasm).makeRefCast(ref, rtt);
 }
 
 Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s) {
-  auto ret = allocator.alloc<BrOnCast>();
-  WASM_UNREACHABLE("TODO (gc): br_on_cast");
-  ret->finalize();
-  return ret;
+  auto name = getLabel(*s[1]);
+  auto heapType = parseHeapType(*s[2]);
+  auto* ref = parseExpression(*s[3]);
+  auto* rtt = parseExpression(*s[4]);
+  validateHeapTypeUsingChild(rtt, heapType, s);
+  return Builder(wasm).makeBrOnCast(name, heapType, ref, rtt);
 }
 
 Expression* SExpressionWasmBuilder::makeRttCanon(Element& s) {
-  auto ret = allocator.alloc<RttCanon>();
-  WASM_UNREACHABLE("TODO (gc): rtt.canon");
-  ret->finalize();
-  return ret;
+  return Builder(wasm).makeRttCanon(parseHeapType(*s[1]));
 }
 
 Expression* SExpressionWasmBuilder::makeRttSub(Element& s) {
-  auto ret = allocator.alloc<RttSub>();
-  WASM_UNREACHABLE("TODO (gc): rtt.sub");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto parent = parseExpression(*s[2]);
+  return Builder(wasm).makeRttSub(heapType, parent);
 }
 
 Expression* SExpressionWasmBuilder::makeStructNew(Element& s, bool default_) {
-  auto ret = allocator.alloc<StructNew>();
-  WASM_UNREACHABLE("TODO (gc): struct.new");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto* rtt = parseExpression(*s[2]);
+  validateHeapTypeUsingChild(rtt, heapType, s);
+  auto numOperands = s.size() - 3;
+  if (default_ && numOperands > 0) {
+    throw ParseException(
+      "arguments provided for struct.new_with_default", s.line, s.col);
+  }
+  std::vector<Expression*> operands;
+  operands.resize(numOperands);
+  for (Index i = 0; i < numOperands; i++) {
+    operands[i] = parseExpression(*s[i + 3]);
+  }
+  return Builder(wasm).makeStructNew(rtt, operands);
 }
 
-Expression* SExpressionWasmBuilder::makeStructGet(Element& s) {
-  auto ret = allocator.alloc<StructGet>();
-  WASM_UNREACHABLE("TODO (gc): struct.get");
-  ret->finalize();
-  return ret;
+Index SExpressionWasmBuilder::getStructIndex(const HeapType& type, Element& s) {
+  if (s.dollared()) {
+    auto name = s.str();
+    auto struct_ = type.getStruct();
+    auto& fields = struct_.fields;
+    for (Index i = 0; i < fields.size(); i++) {
+      if (fields[i].name == name) {
+        return i;
+      }
+    }
+    throw ParseException("bad struct name", s.line, s.col);
+  }
+  // this is a numeric index
+  return atoi(s.c_str());
 }
 
 Expression* SExpressionWasmBuilder::makeStructGet(Element& s, bool signed_) {
-  auto ret = allocator.alloc<StructGet>();
-  WASM_UNREACHABLE("TODO (gc): struct.get_s/u");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto index = getStructIndex(heapType, *s[2]);
+  auto type = heapType.getStruct().fields[index].type;
+  auto ref = parseExpression(*s[3]);
+  validateHeapTypeUsingChild(ref, heapType, s);
+  return Builder(wasm).makeStructGet(index, ref, type, signed_);
 }
 
 Expression* SExpressionWasmBuilder::makeStructSet(Element& s) {
-  auto ret = allocator.alloc<StructSet>();
-  WASM_UNREACHABLE("TODO (gc): struct.set");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto index = getStructIndex(heapType, *s[2]);
+  auto ref = parseExpression(*s[3]);
+  validateHeapTypeUsingChild(ref, heapType, s);
+  auto value = parseExpression(*s[4]);
+  return Builder(wasm).makeStructSet(index, ref, value);
 }
 
 Expression* SExpressionWasmBuilder::makeArrayNew(Element& s, bool default_) {
-  auto ret = allocator.alloc<ArrayNew>();
-  WASM_UNREACHABLE("TODO (gc): array.new");
-  ret->finalize();
-  return ret;
-}
-
-Expression* SExpressionWasmBuilder::makeArrayGet(Element& s) {
-  auto ret = allocator.alloc<ArrayGet>();
-  WASM_UNREACHABLE("TODO (gc): array.get");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto* rtt = parseExpression(*s[2]);
+  validateHeapTypeUsingChild(rtt, heapType, s);
+  auto* size = parseExpression(*s[3]);
+  Expression* init = nullptr;
+  if (!default_) {
+    init = parseExpression(*s[4]);
+  }
+  return Builder(wasm).makeArrayNew(rtt, size, init);
 }
 
 Expression* SExpressionWasmBuilder::makeArrayGet(Element& s, bool signed_) {
-  auto ret = allocator.alloc<ArrayGet>();
-  WASM_UNREACHABLE("TODO (gc): array.get_s/u");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto ref = parseExpression(*s[2]);
+  validateHeapTypeUsingChild(ref, heapType, s);
+  auto index = parseExpression(*s[3]);
+  return Builder(wasm).makeArrayGet(ref, index, signed_);
 }
 
 Expression* SExpressionWasmBuilder::makeArraySet(Element& s) {
-  auto ret = allocator.alloc<ArraySet>();
-  WASM_UNREACHABLE("TODO (gc): array.set");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto ref = parseExpression(*s[2]);
+  validateHeapTypeUsingChild(ref, heapType, s);
+  auto index = parseExpression(*s[3]);
+  auto value = parseExpression(*s[4]);
+  return Builder(wasm).makeArraySet(ref, index, value);
 }
 
 Expression* SExpressionWasmBuilder::makeArrayLen(Element& s) {
-  auto ret = allocator.alloc<ArrayLen>();
-  WASM_UNREACHABLE("TODO (gc): array.len");
-  ret->finalize();
-  return ret;
+  auto heapType = parseHeapType(*s[1]);
+  auto ref = parseExpression(*s[2]);
+  validateHeapTypeUsingChild(ref, heapType, s);
+  return Builder(wasm).makeArrayLen(ref);
 }
 
 // converts an s-expression string representing binary data into an output
@@ -2185,7 +2314,7 @@
   wasm.memory.shared = false;
   Index i = 1;
   if (s[i]->dollared()) {
-    wasm.memory.name = s[i++]->str();
+    wasm.memory.setExplicitName(s[i++]->str());
   }
   i = parseMemoryIndex(s, i);
   Name importModule, importBase;
@@ -2216,7 +2345,7 @@
       // (memory (data ..)) format
       auto j = parseMemoryIndex(inner, 1);
       auto offset = allocator.alloc<Const>()->set(Literal(int32_t(0)));
-      parseInnerData(inner, j, offset, false);
+      parseInnerData(inner, j, {}, offset, false);
       wasm.memory.initial = wasm.memory.segments[0].data.size();
       return;
     }
@@ -2261,6 +2390,10 @@
   bool isPassive = false;
   Expression* offset = nullptr;
   Index i = 1;
+  Name name;
+  if (s[i]->dollared()) {
+    name = s[i++]->str();
+  }
   if (s[i]->isStr()) {
     // data is passive or named
     if (s[i]->str() == PASSIVE) {
@@ -2274,13 +2407,11 @@
   if (s.size() != 3 && s.size() != 4) {
     throw ParseException("Unexpected data items", s.line, s.col);
   }
-  parseInnerData(s, s.size() - 1, offset, isPassive);
+  parseInnerData(s, s.size() - 1, name, offset, isPassive);
 }
 
-void SExpressionWasmBuilder::parseInnerData(Element& s,
-                                            Index i,
-                                            Expression* offset,
-                                            bool isPassive) {
+void SExpressionWasmBuilder::parseInnerData(
+  Element& s, Index i, Name name, Expression* offset, bool isPassive) {
   std::vector<char> data;
   while (i < s.size()) {
     const char* input = s[i++]->c_str();
@@ -2289,7 +2420,7 @@
     }
   }
   wasm.memory.segments.emplace_back(
-    isPassive, offset, data.data(), data.size());
+    name, isPassive, offset, data.data(), data.size());
 }
 
 void SExpressionWasmBuilder::parseExport(Element& s) {
@@ -2358,7 +2489,8 @@
              (*s[3])[newStyleInner]->dollared()) {
     name = (*s[3])[newStyleInner++]->str();
   }
-  if (!name.is()) {
+  bool hasExplicitName = name.is();
+  if (!hasExplicitName) {
     if (kind == ExternalKind::Function) {
       name = Name("fimport$" + std::to_string(functionCounter++));
       functionNames.push_back(name);
@@ -2366,9 +2498,9 @@
       name = Name("gimport$" + std::to_string(globalCounter++));
       globalNames.push_back(name);
     } else if (kind == ExternalKind::Memory) {
-      name = Name("mimport$" + std::to_string(0));
+      name = Name("mimport$" + std::to_string(memoryCounter++));
     } else if (kind == ExternalKind::Table) {
-      name = Name("timport$" + std::to_string(0));
+      name = Name("timport$" + std::to_string(tableCounter++));
     } else if (kind == ExternalKind::Event) {
       name = Name("eimport$" + std::to_string(eventCounter++));
       eventNames.push_back(name);
@@ -2396,10 +2528,10 @@
     auto func = make_unique<Function>();
 
     j = parseTypeUse(inner, j, func->sig);
-    func->name = name;
+    func->setName(name, hasExplicitName);
     func->module = module;
     func->base = base;
-    functionTypes[name] = func->sig.results;
+    functionSignatures[name] = func->sig;
     wasm.addFunction(func.release());
   } else if (kind == ExternalKind::Global) {
     Type type;
@@ -2415,14 +2547,14 @@
       mutable_ = true;
     }
     auto global = make_unique<Global>();
-    global->name = name;
+    global->setName(name, hasExplicitName);
     global->module = module;
     global->base = base;
     global->type = type;
     global->mutable_ = mutable_;
     wasm.addGlobal(global.release());
   } else if (kind == ExternalKind::Table) {
-    wasm.table.name = name;
+    wasm.table.setName(name, hasExplicitName);
     wasm.table.module = module;
     wasm.table.base = base;
     if (j < inner.size() - 1) {
@@ -2440,7 +2572,7 @@
     j++; // funcref
     // ends with the table element type
   } else if (kind == ExternalKind::Memory) {
-    wasm.memory.name = name;
+    wasm.memory.setName(name, hasExplicitName);
     wasm.memory.module = module;
     wasm.memory.base = base;
     if (inner[j]->isList()) {
@@ -2465,7 +2597,7 @@
     }
     event->attribute = atoi(attrElem[1]->c_str());
     j = parseTypeUse(inner, j, event->sig);
-    event->name = name;
+    event->setName(name, hasExplicitName);
     event->module = module;
     event->base = base;
     wasm.addEvent(event.release());
@@ -2480,7 +2612,7 @@
   std::unique_ptr<Global> global = make_unique<Global>();
   size_t i = 1;
   if (s[i]->dollared() && !(s[i]->isStr() && isType(s[i]->str()))) {
-    global->name = s[i++]->str();
+    global->setExplicitName(s[i++]->str());
   } else {
     global->name = Name::fromInt(globalCounter);
   }
@@ -2569,7 +2701,7 @@
     return; // empty table in old notation
   }
   if (s[i]->dollared()) {
-    wasm.table.name = s[i++]->str();
+    wasm.table.setExplicitName(s[i++]->str());
   }
   if (i == s.size()) {
     return;
@@ -2662,30 +2794,102 @@
   wasm.table.segments.push_back(segment);
 }
 
+HeapType SExpressionWasmBuilder::parseHeapType(Element& s) {
+  if (s.isStr()) {
+    // It's a string.
+    if (s.dollared()) {
+      auto it = typeIndices.find(s.str().str);
+      if (it == typeIndices.end()) {
+        throw ParseException("unknown dollared function type", s.line, s.col);
+      }
+      return types[it->second];
+    } else {
+      // It may be a numerical index, or it may be a built-in type name like
+      // "i31".
+      auto* str = s.str().c_str();
+      if (String::isNumber(str)) {
+        size_t offset = atoi(str);
+        if (offset >= types.size()) {
+          throw ParseException("unknown indexed function type", s.line, s.col);
+        }
+        return types[offset];
+      }
+      return stringToHeapType(str, /* prefix = */ false);
+    }
+  }
+  // It's a list.
+  if (*s[0] == FUNC) {
+    std::vector<Type> params;
+    std::vector<Type> results;
+    for (size_t k = 1; k < s.size(); k++) {
+      Element& curr = *s[k];
+      if (elementStartsWith(curr, PARAM)) {
+        auto newParams = parseParamOrLocal(curr);
+        params.insert(params.end(), newParams.begin(), newParams.end());
+      } else if (elementStartsWith(curr, RESULT)) {
+        auto newResults = parseResults(curr);
+        results.insert(results.end(), newResults.begin(), newResults.end());
+      }
+    }
+    return Signature(Type(params), Type(results));
+  }
+  // It's a struct or an array.
+  auto parseField = [&](Element* t) {
+    Mutability mutable_ = Immutable;
+    // t is a list, containing either
+    //   TYPE
+    // or
+    //   (field TYPE)
+    // or
+    //   (field $name TYPE)
+    Name name;
+    if (elementStartsWith(t, FIELD)) {
+      if (t->size() == 3) {
+        name = (*t)[1]->str();
+      }
+      t = (*t)[t->size() - 1];
+    }
+    // The element may also be (mut (..)).
+    if (elementStartsWith(t, MUT)) {
+      mutable_ = Mutable;
+      t = (*t)[1];
+    }
+    if (t->isStr()) {
+      // t is a simple string name like "i32". It can be a normal wasm type, or
+      // one of the special types only available in fields.
+      if (*t == I8) {
+        return Field(Field::i8, mutable_, name);
+      } else if (*t == I16) {
+        return Field(Field::i16, mutable_, name);
+      }
+    }
+    // Otherwise it's an arbitrary type.
+    return Field(elementToType(*t), mutable_, name);
+  };
+  if (elementStartsWith(s, STRUCT)) {
+    FieldList fields;
+    for (size_t k = 1; k < s.size(); k++) {
+      fields.emplace_back(parseField(s[k]));
+    }
+    return Struct(fields);
+  }
+  if (elementStartsWith(s, ARRAY)) {
+    return Array(parseField(s[1]));
+  }
+  throw ParseException("invalid heap type", s.line, s.col);
+}
+
 void SExpressionWasmBuilder::parseType(Element& s) {
-  std::vector<Type> params;
-  std::vector<Type> results;
   size_t i = 1;
   if (s[i]->isStr()) {
     std::string name = s[i]->str().str;
-    if (signatureIndices.find(name) != signatureIndices.end()) {
+    if (typeIndices.find(name) != typeIndices.end()) {
       throw ParseException("duplicate function type", s.line, s.col);
     }
-    signatureIndices[name] = signatures.size();
+    typeIndices[name] = types.size();
     i++;
   }
-  Element& func = *s[i];
-  for (size_t k = 1; k < func.size(); k++) {
-    Element& curr = *func[k];
-    if (elementStartsWith(curr, PARAM)) {
-      auto newParams = parseParamOrLocal(curr);
-      params.insert(params.end(), newParams.begin(), newParams.end());
-    } else if (elementStartsWith(curr, RESULT)) {
-      auto newResults = parseResults(curr);
-      results.insert(results.end(), newResults.begin(), newResults.end());
-    }
-  }
-  signatures.emplace_back(Type(params), Type(results));
+  types.emplace_back(parseHeapType(*s[i]));
 }
 
 void SExpressionWasmBuilder::parseEvent(Element& s, bool preParseImport) {
@@ -2695,7 +2899,7 @@
   // Parse name
   if (s[i]->isStr() && s[i]->dollared()) {
     auto& inner = *s[i++];
-    event->name = inner.str();
+    event->setExplicitName(inner.str());
     if (wasm.getEventOrNull(event->name)) {
       throw ParseException("duplicate event", inner.line, inner.col);
     }
@@ -2773,6 +2977,21 @@
   }
 
   wasm.addEvent(event.release());
+}
+
+void SExpressionWasmBuilder::validateHeapTypeUsingChild(Expression* child,
+                                                        HeapType heapType,
+                                                        Element& s) {
+  if (child->type == Type::unreachable) {
+    return;
+  }
+  if ((!child->type.isRef() && !child->type.isRtt()) ||
+      child->type.getHeapType() != heapType) {
+    throw ParseException("bad heap type: expected " + heapType.toString() +
+                           " but found " + child->type.toString(),
+                         s.line,
+                         s.col);
+  }
 }
 
 } // namespace wasm
diff --git a/binaryen/src/wasm/wasm-stack.cpp b/binaryen/src/wasm/wasm-stack.cpp
--- a/binaryen/src/wasm/wasm-stack.cpp
+++ b/binaryen/src/wasm/wasm-stack.cpp
@@ -20,13 +20,15 @@
 
 namespace wasm {
 
+static Name IMPOSSIBLE_CONTINUE("impossible-continue");
+
 void BinaryInstWriter::emitResultType(Type type) {
   if (type == Type::unreachable) {
-    o << binaryType(Type::none);
+    parent.writeType(Type::none);
   } else if (type.isTuple()) {
     o << S32LEB(parent.getTypeIndex(Signature(Type::none, type)));
   } else {
-    o << binaryType(type);
+    parent.writeType(type);
   }
 }
 
@@ -351,7 +353,7 @@
   o << int8_t(BinaryConsts::AtomicPrefix);
 
 #define CASE_FOR_OP(Op)                                                        \
-  case Op:                                                                     \
+  case RMW##Op:                                                                \
     switch (curr->type.getBasic()) {                                           \
       case Type::i32:                                                          \
         switch (curr->bytes) {                                                 \
@@ -558,6 +560,18 @@
     case QFMSF64x2:
       o << U32LEB(BinaryConsts::F64x2QFMS);
       break;
+    case SignSelectVec8x16:
+      o << U32LEB(BinaryConsts::V8x16SignSelect);
+      break;
+    case SignSelectVec16x8:
+      o << U32LEB(BinaryConsts::V16x8SignSelect);
+      break;
+    case SignSelectVec32x4:
+      o << U32LEB(BinaryConsts::V32x4SignSelect);
+      break;
+    case SignSelectVec64x2:
+      o << U32LEB(BinaryConsts::V64x2SignSelect);
+      break;
   }
 }
 
@@ -647,6 +661,53 @@
   emitMemoryAccess(curr->align, /*(unused) bytes=*/0, curr->offset);
 }
 
+void BinaryInstWriter::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+  o << int8_t(BinaryConsts::SIMDPrefix);
+  switch (curr->op) {
+    case LoadLaneVec8x16:
+      o << U32LEB(BinaryConsts::V128Load8Lane);
+      break;
+    case LoadLaneVec16x8:
+      o << U32LEB(BinaryConsts::V128Load16Lane);
+      break;
+    case LoadLaneVec32x4:
+      o << U32LEB(BinaryConsts::V128Load32Lane);
+      break;
+    case LoadLaneVec64x2:
+      o << U32LEB(BinaryConsts::V128Load64Lane);
+      break;
+    case StoreLaneVec8x16:
+      o << U32LEB(BinaryConsts::V128Store8Lane);
+      break;
+    case StoreLaneVec16x8:
+      o << U32LEB(BinaryConsts::V128Store16Lane);
+      break;
+    case StoreLaneVec32x4:
+      o << U32LEB(BinaryConsts::V128Store32Lane);
+      break;
+    case StoreLaneVec64x2:
+      o << U32LEB(BinaryConsts::V128Store64Lane);
+      break;
+  }
+  assert(curr->align);
+  emitMemoryAccess(curr->align, /*(unused) bytes=*/0, curr->offset);
+  o << curr->index;
+}
+
+void BinaryInstWriter::visitPrefetch(Prefetch* curr) {
+  o << int8_t(BinaryConsts::SIMDPrefix);
+  switch (curr->op) {
+    case PrefetchTemporal:
+      o << U32LEB(BinaryConsts::PrefetchT);
+      break;
+    case PrefetchNontemporal:
+      o << U32LEB(BinaryConsts::PrefetchNT);
+      break;
+  }
+  assert(curr->align);
+  emitMemoryAccess(curr->align, /*(unused) bytes=*/0, curr->offset);
+}
+
 void BinaryInstWriter::visitMemoryInit(MemoryInit* curr) {
   o << int8_t(BinaryConsts::MiscPrefix);
   o << U32LEB(BinaryConsts::MemoryInit);
@@ -938,6 +999,10 @@
       o << int8_t(BinaryConsts::SIMDPrefix)
         << U32LEB(BinaryConsts::I8x16Bitmask);
       break;
+    case PopcntVecI8x16:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I8x16Popcnt);
+      break;
     case AbsVecI16x8:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8Abs);
       break;
@@ -977,13 +1042,9 @@
     case NegVecI64x2:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Neg);
       break;
-    case AnyTrueVecI64x2:
-      o << int8_t(BinaryConsts::SIMDPrefix)
-        << U32LEB(BinaryConsts::I64x2AnyTrue);
-      break;
-    case AllTrueVecI64x2:
+    case BitmaskVecI64x2:
       o << int8_t(BinaryConsts::SIMDPrefix)
-        << U32LEB(BinaryConsts::I64x2AllTrue);
+        << U32LEB(BinaryConsts::I64x2Bitmask);
       break;
     case AbsVecF32x4:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Abs);
@@ -1029,6 +1090,22 @@
       o << int8_t(BinaryConsts::SIMDPrefix)
         << U32LEB(BinaryConsts::F64x2Nearest);
       break;
+    case ExtAddPairwiseSVecI8x16ToI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8ExtAddPairWiseSI8x16);
+      break;
+    case ExtAddPairwiseUVecI8x16ToI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8ExtAddPairWiseUI8x16);
+      break;
+    case ExtAddPairwiseSVecI16x8ToI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4ExtAddPairWiseSI16x8);
+      break;
+    case ExtAddPairwiseUVecI16x8ToI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4ExtAddPairWiseUI16x8);
+      break;
     case TruncSatSVecF32x4ToVecI32x4:
       o << int8_t(BinaryConsts::SIMDPrefix)
         << U32LEB(BinaryConsts::I32x4TruncSatSF32x4);
@@ -1093,6 +1170,22 @@
       o << int8_t(BinaryConsts::SIMDPrefix)
         << U32LEB(BinaryConsts::I32x4WidenHighUI16x8);
       break;
+    case WidenLowSVecI32x4ToVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2WidenLowSI32x4);
+      break;
+    case WidenHighSVecI32x4ToVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2WidenHighSI32x4);
+      break;
+    case WidenLowUVecI32x4ToVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2WidenLowUI32x4);
+      break;
+    case WidenHighUVecI32x4ToVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2WidenHighUI32x4);
+      break;
     case InvalidUnary:
       WASM_UNREACHABLE("invalid unary op");
   }
@@ -1422,6 +1515,9 @@
     case GeUVecI32x4:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4GeU);
       break;
+    case EqVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Eq);
+      break;
     case EqVecF32x4:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Eq);
       break;
@@ -1550,6 +1646,26 @@
     case AvgrUVecI16x8:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I16x8AvgrU);
       break;
+    case Q15MulrSatSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8Q15MulrSatS);
+      break;
+    case ExtMulLowSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8ExtMulLowSI8x16);
+      break;
+    case ExtMulHighSVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8ExtMulHighSI8x16);
+      break;
+    case ExtMulLowUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8ExtMulLowUI8x16);
+      break;
+    case ExtMulHighUVecI16x8:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I16x8ExtMulHighUI8x16);
+      break;
     case AddVecI32x4:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I32x4Add);
       break;
@@ -1575,6 +1691,22 @@
       o << int8_t(BinaryConsts::SIMDPrefix)
         << U32LEB(BinaryConsts::I32x4DotSVecI16x8);
       break;
+    case ExtMulLowSVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4ExtMulLowSI16x8);
+      break;
+    case ExtMulHighSVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4ExtMulHighSI16x8);
+      break;
+    case ExtMulLowUVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4ExtMulLowUI16x8);
+      break;
+    case ExtMulHighUVecI32x4:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I32x4ExtMulHighUI16x8);
+      break;
     case AddVecI64x2:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Add);
       break;
@@ -1584,6 +1716,22 @@
     case MulVecI64x2:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::I64x2Mul);
       break;
+    case ExtMulLowSVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2ExtMulLowSI32x4);
+      break;
+    case ExtMulHighSVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2ExtMulHighSI32x4);
+      break;
+    case ExtMulLowUVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2ExtMulLowUI32x4);
+      break;
+    case ExtMulHighUVecI64x2:
+      o << int8_t(BinaryConsts::SIMDPrefix)
+        << U32LEB(BinaryConsts::I64x2ExtMulHighUI32x4);
+      break;
 
     case AddVecF32x4:
       o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Add);
@@ -1665,8 +1813,8 @@
   if (curr->type.isRef()) {
     o << int8_t(BinaryConsts::SelectWithType) << U32LEB(curr->type.size());
     for (size_t i = 0; i < curr->type.size(); i++) {
-      o << binaryType(curr->type != Type::unreachable ? curr->type
-                                                      : Type::none);
+      parent.writeType(curr->type != Type::unreachable ? curr->type
+                                                       : Type::none);
     }
   } else {
     o << int8_t(BinaryConsts::Select);
@@ -1688,8 +1836,8 @@
 }
 
 void BinaryInstWriter::visitRefNull(RefNull* curr) {
-  o << int8_t(BinaryConsts::RefNull)
-    << binaryHeapType(curr->type.getHeapType());
+  o << int8_t(BinaryConsts::RefNull);
+  parent.writeHeapType(curr->type.getHeapType());
 }
 
 void BinaryInstWriter::visitRefIsNull(RefIsNull* curr) {
@@ -1784,69 +1932,116 @@
     << U32LEB(curr->signed_ ? BinaryConsts::I31GetS : BinaryConsts::I31GetU);
 }
 
+void BinaryInstWriter::visitCallRef(CallRef* curr) {
+  o << int8_t(curr->isReturn ? BinaryConsts::RetCallRef
+                             : BinaryConsts::CallRef);
+}
+
 void BinaryInstWriter::visitRefTest(RefTest* curr) {
   o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefTest);
-  WASM_UNREACHABLE("TODO (gc): ref.test");
+  parent.writeHeapType(curr->ref->type.getHeapType());
+  parent.writeHeapType(curr->getCastType().getHeapType());
 }
 
 void BinaryInstWriter::visitRefCast(RefCast* curr) {
   o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefCast);
-  WASM_UNREACHABLE("TODO (gc): ref.cast");
+  parent.writeHeapType(curr->ref->type.getHeapType());
+  parent.writeHeapType(curr->getCastType().getHeapType());
 }
 
 void BinaryInstWriter::visitBrOnCast(BrOnCast* curr) {
-  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnCast);
-  WASM_UNREACHABLE("TODO (gc): br_on_cast");
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnCast)
+    << U32LEB(getBreakIndex(curr->name));
+  parent.writeHeapType(curr->ref->type.getHeapType());
+  parent.writeHeapType(curr->getCastType().getHeapType());
 }
 
 void BinaryInstWriter::visitRttCanon(RttCanon* curr) {
   o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RttCanon);
-  WASM_UNREACHABLE("TODO (gc): rtt.canon");
+  parent.writeHeapType(curr->type.getRtt().heapType);
 }
 
 void BinaryInstWriter::visitRttSub(RttSub* curr) {
   o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RttSub);
-  WASM_UNREACHABLE("TODO (gc): rtt.sub");
+  // FIXME: the binary format may also have an extra heap type and index that
+  //        are not needed
+  parent.writeHeapType(curr->type.getRtt().heapType);
 }
 
 void BinaryInstWriter::visitStructNew(StructNew* curr) {
-  WASM_UNREACHABLE("TODO (gc): struct.new");
+  o << int8_t(BinaryConsts::GCPrefix);
+  if (curr->isWithDefault()) {
+    o << U32LEB(BinaryConsts::StructNewDefaultWithRtt);
+  } else {
+    o << U32LEB(BinaryConsts::StructNewWithRtt);
+  }
+  parent.writeHeapType(curr->rtt->type.getHeapType());
 }
 
 void BinaryInstWriter::visitStructGet(StructGet* curr) {
-  WASM_UNREACHABLE("TODO (gc): struct.get");
+  const auto& heapType = curr->ref->type.getHeapType();
+  const auto& field = heapType.getStruct().fields[curr->index];
+  int8_t op;
+  if (field.type != Type::i32 || field.packedType == Field::not_packed) {
+    op = BinaryConsts::StructGet;
+  } else if (curr->signed_) {
+    op = BinaryConsts::StructGetS;
+  } else {
+    op = BinaryConsts::StructGetU;
+  }
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(op);
+  parent.writeHeapType(heapType);
+  o << U32LEB(curr->index);
 }
 
 void BinaryInstWriter::visitStructSet(StructSet* curr) {
   o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::StructSet);
-  WASM_UNREACHABLE("TODO (gc): struct.set");
+  parent.writeHeapType(curr->ref->type.getHeapType());
+  o << U32LEB(curr->index);
 }
 
 void BinaryInstWriter::visitArrayNew(ArrayNew* curr) {
-  WASM_UNREACHABLE("TODO (gc): array.new");
+  o << int8_t(BinaryConsts::GCPrefix);
+  if (curr->isWithDefault()) {
+    o << U32LEB(BinaryConsts::ArrayNewDefaultWithRtt);
+  } else {
+    o << U32LEB(BinaryConsts::ArrayNewWithRtt);
+  }
+  parent.writeHeapType(curr->rtt->type.getHeapType());
 }
 
 void BinaryInstWriter::visitArrayGet(ArrayGet* curr) {
-  WASM_UNREACHABLE("TODO (gc): array.get");
+  auto heapType = curr->ref->type.getHeapType();
+  const auto& field = heapType.getArray().element;
+  int8_t op;
+  if (field.type != Type::i32 || field.packedType == Field::not_packed) {
+    op = BinaryConsts::ArrayGet;
+  } else if (curr->signed_) {
+    op = BinaryConsts::ArrayGetS;
+  } else {
+    op = BinaryConsts::ArrayGetU;
+  }
+  o << int8_t(BinaryConsts::GCPrefix) << U32LEB(op);
+  parent.writeHeapType(heapType);
 }
 
 void BinaryInstWriter::visitArraySet(ArraySet* curr) {
   o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArraySet);
-  WASM_UNREACHABLE("TODO (gc): array.set");
+  parent.writeHeapType(curr->ref->type.getHeapType());
 }
 
 void BinaryInstWriter::visitArrayLen(ArrayLen* curr) {
   o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArrayLen);
-  WASM_UNREACHABLE("TODO (gc): array.len");
+  parent.writeHeapType(curr->ref->type.getHeapType());
 }
 
 void BinaryInstWriter::emitScopeEnd(Expression* curr) {
   assert(!breakStack.empty());
   breakStack.pop_back();
+  o << int8_t(BinaryConsts::End);
   if (func && !sourceMap) {
-    parent.writeExtraDebugLocation(curr, func, BinaryLocations::End);
+    parent.writeDebugLocationEnd(curr, func);
   }
-  o << int8_t(BinaryConsts::End);
 }
 
 void BinaryInstWriter::emitFunctionEnd() { o << int8_t(BinaryConsts::End); }
@@ -1875,7 +2070,8 @@
     o << U32LEB(func->getNumVars());
     for (Index i = varStart; i < varEnd; i++) {
       mappedLocals[std::make_pair(i, 0)] = i;
-      o << U32LEB(1) << binaryType(func->getLocalType(i));
+      o << U32LEB(1);
+      parent.writeType(func->getLocalType(i));
     }
     return;
   }
@@ -1904,7 +2100,8 @@
   setScratchLocals();
   o << U32LEB(numLocalsByType.size());
   for (auto& typeCount : numLocalsByType) {
-    o << U32LEB(typeCount.second) << binaryType(typeCount.first);
+    o << U32LEB(typeCount.second);
+    parent.writeType(typeCount.first);
   }
 }
 
diff --git a/binaryen/src/wasm/wasm-type.cpp b/binaryen/src/wasm/wasm-type.cpp
--- a/binaryen/src/wasm/wasm-type.cpp
+++ b/binaryen/src/wasm/wasm-type.cpp
@@ -19,885 +19,1377 @@
 #include <shared_mutex>
 #include <sstream>
 #include <unordered_map>
-
-#include "compiler-support.h"
-#include "support/hash.h"
-#include "wasm-features.h"
-#include "wasm-type.h"
-
-namespace wasm {
-
-struct TypeInfo {
-  enum Kind {
-    TupleKind,
-    RefKind,
-    RttKind,
-  } kind;
-  struct Ref {
-    HeapType heapType;
-    bool nullable;
-  };
-  union {
-    Tuple tuple;
-    Ref ref;
-    Rtt rtt;
-  };
-
-  TypeInfo(const Tuple& tuple) : kind(TupleKind), tuple(tuple) {}
-  TypeInfo(Tuple&& tuple) : kind(TupleKind), tuple(std::move(tuple)) {}
-  TypeInfo(const HeapType& heapType, bool nullable)
-    : kind(RefKind), ref{heapType, nullable} {}
-  TypeInfo(HeapType&& heapType, bool nullable)
-    : kind(RefKind), ref{std::move(heapType), nullable} {}
-  TypeInfo(const Rtt& rtt) : kind(RttKind), rtt(rtt) {}
-  TypeInfo(Rtt&& rtt) : kind(RttKind), rtt(std::move(rtt)) {}
-  TypeInfo(const TypeInfo& other) {
-    kind = other.kind;
-    switch (kind) {
-      case TupleKind:
-        new (&tuple) auto(other.tuple);
-        return;
-      case RefKind:
-        new (&ref) auto(other.ref);
-        return;
-      case RttKind:
-        new (&rtt) auto(other.rtt);
-        return;
-    }
-    WASM_UNREACHABLE("unexpected kind");
-  }
-  ~TypeInfo() {
-    switch (kind) {
-      case TupleKind: {
-        tuple.~Tuple();
-        return;
-      }
-      case RefKind: {
-        ref.~Ref();
-        return;
-      }
-      case RttKind: {
-        rtt.~Rtt();
-        return;
-      }
-    }
-    WASM_UNREACHABLE("unexpected kind");
-  }
-
-  constexpr bool isTuple() const { return kind == TupleKind; }
-  constexpr bool isRef() const { return kind == RefKind; }
-  constexpr bool isRtt() const { return kind == RttKind; }
-
-  bool isNullable() const { return kind == RefKind && ref.nullable; }
-
-  bool operator==(const TypeInfo& other) const {
-    if (kind != other.kind) {
-      return false;
-    }
-    switch (kind) {
-      case TupleKind:
-        return tuple == other.tuple;
-      case RefKind:
-        return ref.heapType == other.ref.heapType &&
-               ref.nullable == other.ref.nullable;
-      case RttKind:
-        return rtt == other.rtt;
-    }
-    WASM_UNREACHABLE("unexpected kind");
-  }
-  bool operator!=(const TypeInfo& other) const { return !(*this == other); }
-  TypeInfo& operator=(const TypeInfo& other) {
-    if (&other != this) {
-      this->~TypeInfo();
-      new (this) auto(other);
-    }
-    return *this;
-  }
-
-  std::string toString() const;
-};
-
-std::ostream& operator<<(std::ostream&, TypeInfo);
-
-} // namespace wasm
-
-namespace std {
-
-template<> class hash<wasm::TypeList> {
-public:
-  size_t operator()(const wasm::TypeList& types) const {
-    auto digest = wasm::hash(types.size());
-    for (auto type : types) {
-      wasm::rehash(digest, type);
-    }
-    return digest;
-  }
-};
-
-template<> class hash<wasm::FieldList> {
-public:
-  size_t operator()(const wasm::FieldList& fields) const {
-    auto digest = wasm::hash(fields.size());
-    for (auto field : fields) {
-      wasm::rehash(digest, field);
-    }
-    return digest;
-  }
-};
-
-template<> class hash<wasm::TypeInfo> {
-public:
-  size_t operator()(const wasm::TypeInfo& info) const {
-    auto digest = wasm::hash(info.kind);
-    switch (info.kind) {
-      case wasm::TypeInfo::TupleKind: {
-        wasm::rehash(digest, info.tuple);
-        return digest;
-      }
-      case wasm::TypeInfo::RefKind: {
-        wasm::rehash(digest, info.ref.heapType);
-        wasm::rehash(digest, info.ref.nullable);
-        return digest;
-      }
-      case wasm::TypeInfo::RttKind: {
-        wasm::rehash(digest, info.rtt);
-        return digest;
-      }
-    }
-    WASM_UNREACHABLE("unexpected kind");
-  }
-};
-
-size_t hash<wasm::Type>::operator()(const wasm::Type& type) const {
-  return wasm::hash(type.getID());
-}
-
-size_t hash<wasm::Tuple>::operator()(const wasm::Tuple& tuple) const {
-  return wasm::hash(tuple.types);
-}
-
-size_t hash<wasm::Signature>::operator()(const wasm::Signature& sig) const {
-  auto digest = wasm::hash(sig.params);
-  wasm::rehash(digest, sig.results);
-  return digest;
-}
-
-size_t hash<wasm::Field>::operator()(const wasm::Field& field) const {
-  auto digest = wasm::hash(field.type);
-  wasm::rehash(digest, field.packedType);
-  wasm::rehash(digest, field.mutable_);
-  return digest;
-}
-
-size_t hash<wasm::Struct>::operator()(const wasm::Struct& struct_) const {
-  return wasm::hash(struct_.fields);
-}
-
-size_t hash<wasm::Array>::operator()(const wasm::Array& array) const {
-  return wasm::hash(array.element);
-}
-
-size_t hash<wasm::HeapType>::operator()(const wasm::HeapType& heapType) const {
-  auto digest = wasm::hash(heapType.kind);
-  switch (heapType.kind) {
-    case wasm::HeapType::FuncKind:
-    case wasm::HeapType::ExternKind:
-    case wasm::HeapType::AnyKind:
-    case wasm::HeapType::EqKind:
-    case wasm::HeapType::I31Kind:
-    case wasm::HeapType::ExnKind:
-      return digest;
-    case wasm::HeapType::SignatureKind:
-      wasm::rehash(digest, heapType.signature);
-      return digest;
-    case wasm::HeapType::StructKind:
-      wasm::rehash(digest, heapType.struct_);
-      return digest;
-    case wasm::HeapType::ArrayKind:
-      wasm::rehash(digest, heapType.array);
-      return digest;
-  }
-  WASM_UNREACHABLE("unexpected kind");
-}
-
-size_t hash<wasm::Rtt>::operator()(const wasm::Rtt& rtt) const {
-  auto digest = wasm::hash(rtt.depth);
-  wasm::rehash(digest, rtt.heapType);
-  return digest;
-}
-
-} // namespace std
-
-namespace wasm {
-
-namespace {
-
-std::mutex mutex;
-
-// Track unique_ptrs for constructed types to avoid leaks
-std::vector<std::unique_ptr<TypeInfo>> constructedTypes;
-
-// Maps from constructed types to the canonical Type ID.
-std::unordered_map<TypeInfo, uintptr_t> indices = {
-  // If a Type is constructed from a list of types, the list of types becomes
-  // implicitly converted to a TypeInfo before canonicalizing its id. This is
-  // also the case if a list of just one type is provided, even though such a
-  // list of types will be canonicalized to the BasicID of the single type. As
-  // such, the following entries are solely placeholders to enable the lookup
-  // of lists of just one type to the BasicID of the single type.
-  {TypeInfo(Tuple()), Type::none},
-  {TypeInfo({Type::unreachable}), Type::unreachable},
-  {TypeInfo({Type::i32}), Type::i32},
-  {TypeInfo({Type::i64}), Type::i64},
-  {TypeInfo({Type::f32}), Type::f32},
-  {TypeInfo({Type::f64}), Type::f64},
-  {TypeInfo({Type::v128}), Type::v128},
-  {TypeInfo({Type::funcref}), Type::funcref},
-  {TypeInfo(HeapType(HeapType::FuncKind), true), Type::funcref},
-  {TypeInfo({Type::externref}), Type::externref},
-  {TypeInfo(HeapType(HeapType::ExternKind), true), Type::externref},
-  {TypeInfo({Type::exnref}), Type::exnref},
-  {TypeInfo(HeapType(HeapType::ExnKind), true), Type::exnref},
-  {TypeInfo({Type::anyref}), Type::anyref},
-  {TypeInfo(HeapType(HeapType::AnyKind), true), Type::anyref},
-  {TypeInfo({Type::eqref}), Type::eqref},
-  {TypeInfo(HeapType(HeapType::EqKind), true), Type::eqref},
-  {TypeInfo({Type::i31ref}), Type::i31ref},
-  {TypeInfo(HeapType(HeapType::I31Kind), false), Type::i31ref},
-};
-
-} // anonymous namespace
-
-static uintptr_t canonicalize(const TypeInfo& info) {
-  std::lock_guard<std::mutex> lock(mutex);
-  auto indexIt = indices.find(info);
-  if (indexIt != indices.end()) {
-    return indexIt->second;
-  }
-  auto ptr = std::make_unique<TypeInfo>(info);
-  auto id = uintptr_t(ptr.get());
-  constructedTypes.push_back(std::move(ptr));
-  assert(id > Type::_last_basic_id);
-  indices[info] = id;
-  return id;
-}
-
-static TypeInfo* getTypeInfo(const Type& type) {
-  return (TypeInfo*)type.getID();
-}
-
-Type::Type(std::initializer_list<Type> types) : Type(Tuple(types)) {}
-
-Type::Type(const Tuple& tuple) {
-  auto& types = tuple.types;
-#ifndef NDEBUG
-  for (Type t : types) {
-    assert(t.isSingle());
-  }
-#endif
-  if (types.size() == 0) {
-    id = none;
-    return;
-  }
-  if (types.size() == 1) {
-    *this = types[0];
-    return;
-  }
-  id = canonicalize(TypeInfo(tuple));
-}
-
-Type::Type(const HeapType& heapType, bool nullable) {
-#ifndef NDEBUG
-  switch (heapType.kind) {
-    case HeapType::FuncKind:
-    case HeapType::ExternKind:
-    case HeapType::AnyKind:
-    case HeapType::EqKind:
-    case HeapType::I31Kind:
-    case HeapType::ExnKind:
-    case HeapType::SignatureKind:
-      break;
-    case HeapType::StructKind:
-      for (Field f : heapType.struct_.fields) {
-        assert(f.type.isSingle());
-      }
-      break;
-    case HeapType::ArrayKind:
-      assert(heapType.array.element.type.isSingle());
-      break;
-  }
-#endif
-  id = canonicalize(TypeInfo(heapType, nullable));
-}
-
-Type::Type(const Rtt& rtt) { id = canonicalize(TypeInfo(rtt)); }
-
-bool Type::isTuple() const {
-  if (isBasic()) {
-    return false;
-  } else {
-    return getTypeInfo(*this)->isTuple();
-  }
-}
-
-bool Type::isRef() const {
-  if (isBasic()) {
-    return id >= funcref && id <= i31ref;
-  } else {
-    return getTypeInfo(*this)->isRef();
-  }
-}
-
-bool Type::isFunction() const {
-  if (isBasic()) {
-    return id == funcref;
-  } else {
-    auto* info = getTypeInfo(*this);
-    return info->isRef() && info->ref.heapType.isSignature();
-  }
-}
-
-bool Type::isException() const {
-  if (isBasic()) {
-    return id == exnref;
-  } else {
-    auto* info = getTypeInfo(*this);
-    return info->isRef() && info->ref.heapType.isException();
-  }
-}
-
-bool Type::isNullable() const {
-  if (isBasic()) {
-    return id >= funcref && id <= eqref; // except i31ref
-  } else {
-    return getTypeInfo(*this)->isNullable();
-  }
-}
-
-bool Type::isRtt() const {
-  if (isBasic()) {
-    return false;
-  } else {
-    return getTypeInfo(*this)->isRtt();
-  }
-}
-
-bool Type::operator<(const Type& other) const {
-  return std::lexicographical_compare(begin(),
-                                      end(),
-                                      other.begin(),
-                                      other.end(),
-                                      [](const Type& a, const Type& b) {
-                                        TODO_SINGLE_COMPOUND(a);
-                                        TODO_SINGLE_COMPOUND(b);
-                                        return a.getBasic() < b.getBasic();
-                                      });
-}
-
-unsigned Type::getByteSize() const {
-  // TODO: alignment?
-  auto getSingleByteSize = [](Type t) {
-    switch (t.getBasic()) {
-      case Type::i32:
-      case Type::f32:
-        return 4;
-      case Type::i64:
-      case Type::f64:
-        return 8;
-      case Type::v128:
-        return 16;
-      case Type::funcref:
-      case Type::externref:
-      case Type::exnref:
-      case Type::anyref:
-      case Type::eqref:
-      case Type::i31ref:
-      case Type::none:
-      case Type::unreachable:
-        break;
-    }
-    WASM_UNREACHABLE("invalid type");
-  };
-
-  if (isTuple()) {
-    unsigned size = 0;
-    for (const auto& t : *this) {
-      size += getSingleByteSize(t);
-    }
-    return size;
-  }
-  return getSingleByteSize(*this);
-}
-
-Type Type::reinterpret() const {
-  assert(!isTuple() && "Unexpected tuple type");
-  switch ((*begin()).getBasic()) {
-    case Type::i32:
-      return f32;
-    case Type::i64:
-      return f64;
-    case Type::f32:
-      return i32;
-    case Type::f64:
-      return i64;
-    default:
-      WASM_UNREACHABLE("invalid type");
-  }
-}
-
-FeatureSet Type::getFeatures() const {
-  auto getSingleFeatures = [](Type t) -> FeatureSet {
-    TODO_SINGLE_COMPOUND(t);
-    switch (t.getBasic()) {
-      case Type::v128:
-        return FeatureSet::SIMD;
-      case Type::funcref:
-      case Type::externref:
-        return FeatureSet::ReferenceTypes;
-      case Type::exnref:
-        return FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling;
-      case Type::anyref:
-      case Type::eqref:
-      case Type::i31ref:
-        return FeatureSet::ReferenceTypes | FeatureSet::GC;
-      default:
-        return FeatureSet::MVP;
-    }
-  };
-
-  if (isTuple()) {
-    FeatureSet feats = FeatureSet::Multivalue;
-    for (const auto& t : *this) {
-      feats |= getSingleFeatures(t);
-    }
-    return feats;
-  }
-  return getSingleFeatures(*this);
-}
-
-HeapType Type::getHeapType() const {
-  if (isRef()) {
-    if (isCompound()) {
-      return getTypeInfo(*this)->ref.heapType;
-    }
-    switch (getBasic()) {
-      case funcref:
-        return HeapType::FuncKind;
-      case externref:
-        return HeapType::ExternKind;
-      case exnref:
-        return HeapType::ExnKind;
-      case anyref:
-        return HeapType::AnyKind;
-      case eqref:
-        return HeapType::EqKind;
-      case i31ref:
-        return HeapType::I31Kind;
-      default:
-        break;
-    }
-  }
-  WASM_UNREACHABLE("unexpected type");
-}
-
-Type Type::get(unsigned byteSize, bool float_) {
-  if (byteSize < 4) {
-    return Type::i32;
-  }
-  if (byteSize == 4) {
-    return float_ ? Type::f32 : Type::i32;
-  }
-  if (byteSize == 8) {
-    return float_ ? Type::f64 : Type::i64;
-  }
-  if (byteSize == 16) {
-    return Type::v128;
-  }
-  WASM_UNREACHABLE("invalid size");
-}
-
-bool Type::isSubType(Type left, Type right) {
-  if (left == right) {
-    return true;
-  }
-  if (left.isRef() && right.isRef()) {
-    return right == Type::anyref ||
-           (left == Type::i31ref && right == Type::eqref);
-  }
-  if (left.isTuple() && right.isTuple()) {
-    if (left.size() != right.size()) {
-      return false;
-    }
-    for (size_t i = 0; i < left.size(); ++i) {
-      if (!isSubType(left[i], right[i])) {
-        return false;
-      }
-    }
-    return true;
-  }
-  return false;
-}
-
-Type Type::getLeastUpperBound(Type a, Type b) {
-  if (a == b) {
-    return a;
-  }
-  if (a == Type::unreachable) {
-    return b;
-  }
-  if (b == Type::unreachable) {
-    return a;
-  }
-  if (a.size() != b.size()) {
-    return Type::none; // a poison value that must not be consumed
-  }
-  if (a.isRef()) {
-    if (b.isRef()) {
-      if ((a == Type::i31ref && b == Type::eqref) ||
-          (a == Type::eqref && b == Type::i31ref)) {
-        return Type::eqref;
-      }
-      // The LUB of two different reference types is anyref, which may or may
-      // not be a valid type depending on whether the anyref feature is enabled.
-      // When anyref is disabled, it is possible for the finalization of invalid
-      // code to introduce a use of anyref via this function, but that is not a
-      // problem because it will be caught and rejected by validation.
-      return Type::anyref;
-    }
-    return Type::none;
-  }
-  if (a.isTuple()) {
-    TypeList types;
-    types.resize(a.size());
-    for (size_t i = 0; i < types.size(); ++i) {
-      types[i] = getLeastUpperBound(a[i], b[i]);
-      if (types[i] == Type::none) {
-        return Type::none;
-      }
-    }
-    return Type(types);
-  }
-  return Type::none;
-}
-
-Type::Iterator Type::end() const {
-  if (isTuple()) {
-    return Iterator(this, getTypeInfo(*this)->tuple.types.size());
-  } else {
-    // TODO: unreachable is special and expands to {unreachable} currently.
-    // see also: https://github.com/WebAssembly/binaryen/issues/3062
-    return Iterator(this, size_t(id != Type::none));
-  }
-}
-
-const Type& Type::Iterator::operator*() const {
-  if (parent->isTuple()) {
-    return getTypeInfo(*parent)->tuple.types[index];
-  } else {
-    // TODO: see comment in Type::end()
-    assert(index == 0 && parent->id != Type::none && "Index out of bounds");
-    return *parent;
-  }
-}
-
-const Type& Type::operator[](size_t index) const {
-  if (isTuple()) {
-    return getTypeInfo(*this)->tuple.types[index];
-  } else {
-    assert(index == 0 && "Index out of bounds");
-    return *begin();
-  }
-}
-
-HeapType::HeapType(const HeapType& other) : kind(other.kind) {
-  switch (kind) {
-    case FuncKind:
-    case ExternKind:
-    case AnyKind:
-    case EqKind:
-    case I31Kind:
-    case ExnKind:
-      return;
-    case SignatureKind:
-      new (&signature) auto(other.signature);
-      return;
-    case StructKind:
-      new (&struct_) auto(other.struct_);
-      return;
-    case ArrayKind:
-      new (&array) auto(other.array);
-      return;
-  }
-  WASM_UNREACHABLE("unexpected kind");
-}
-
-HeapType::~HeapType() {
-  switch (kind) {
-    case FuncKind:
-    case ExternKind:
-    case AnyKind:
-    case EqKind:
-    case I31Kind:
-    case ExnKind:
-      return;
-    case SignatureKind:
-      signature.~Signature();
-      return;
-    case StructKind:
-      struct_.~Struct();
-      return;
-    case ArrayKind:
-      array.~Array();
-      return;
-  }
-}
-
-bool HeapType::operator==(const HeapType& other) const {
-  if (kind != other.kind) {
-    return false;
-  }
-  switch (kind) {
-    case FuncKind:
-    case ExternKind:
-    case AnyKind:
-    case EqKind:
-    case I31Kind:
-    case ExnKind:
-      return true;
-    case SignatureKind:
-      return signature == other.signature;
-    case StructKind:
-      return struct_ == other.struct_;
-    case ArrayKind:
-      return array == other.array;
-  }
-  WASM_UNREACHABLE("unexpected kind");
-}
-
-HeapType& HeapType::operator=(const HeapType& other) {
-  if (&other != this) {
-    this->~HeapType();
-    new (this) auto(other);
-  }
-  return *this;
-}
-
-namespace {
-
-std::ostream&
-printPrefixedTypes(std::ostream& os, const char* prefix, Type type) {
-  os << '(' << prefix;
-  for (const auto& t : type) {
-    os << " " << t;
-  }
-  os << ')';
-  return os;
-}
-
-template<typename T> std::string genericToString(const T& t) {
-  std::ostringstream ss;
-  ss << t;
-  return ss.str();
-}
-
-} // anonymous namespace
-
-std::string Type::toString() const { return genericToString(*this); }
-
-std::string ParamType::toString() const { return genericToString(*this); }
-
-std::string ResultType::toString() const { return genericToString(*this); }
-
-std::string Tuple::toString() const { return genericToString(*this); }
-
-std::string Signature::toString() const { return genericToString(*this); }
-
-std::string Struct::toString() const { return genericToString(*this); }
-
-std::string Array::toString() const { return genericToString(*this); }
-
-std::string HeapType::toString() const { return genericToString(*this); }
-
-std::string Rtt::toString() const { return genericToString(*this); }
-
-std::string TypeInfo::toString() const { return genericToString(*this); }
-
-bool Signature::operator<(const Signature& other) const {
-  if (results < other.results) {
-    return true;
-  } else if (other.results < results) {
-    return false;
-  } else {
-    return params < other.params;
-  }
-}
-
-std::ostream& operator<<(std::ostream& os, Type type) {
-  if (type.isBasic()) {
-    switch (type.getBasic()) {
-      case Type::none:
-        os << "none";
-        break;
-      case Type::unreachable:
-        os << "unreachable";
-        break;
-      case Type::i32:
-        os << "i32";
-        break;
-      case Type::i64:
-        os << "i64";
-        break;
-      case Type::f32:
-        os << "f32";
-        break;
-      case Type::f64:
-        os << "f64";
-        break;
-      case Type::v128:
-        os << "v128";
-        break;
-      case Type::funcref:
-        os << "funcref";
-        break;
-      case Type::externref:
-        os << "externref";
-        break;
-      case Type::exnref:
-        os << "exnref";
-        break;
-      case Type::anyref:
-        os << "anyref";
-        break;
-      case Type::eqref:
-        os << "eqref";
-        break;
-      case Type::i31ref:
-        os << "i31ref";
-        break;
-    }
-  } else {
-    os << *getTypeInfo(type);
-  }
-  return os;
-}
-
-std::ostream& operator<<(std::ostream& os, ParamType param) {
-  return printPrefixedTypes(os, "param", param.type);
-}
-
-std::ostream& operator<<(std::ostream& os, ResultType param) {
-  return printPrefixedTypes(os, "result", param.type);
-}
-
-std::ostream& operator<<(std::ostream& os, Tuple tuple) {
-  auto& types = tuple.types;
-  auto size = types.size();
-  os << "(";
-  if (size) {
-    os << types[0];
-    for (size_t i = 1; i < size; ++i) {
-      os << " " << types[i];
-    }
-  }
-  return os << ")";
-}
-
-std::ostream& operator<<(std::ostream& os, Signature sig) {
-  os << "(func";
-  if (sig.params.getID() != Type::none) {
-    os << " ";
-    printPrefixedTypes(os, "param", sig.params);
-  }
-  if (sig.results.getID() != Type::none) {
-    os << " ";
-    printPrefixedTypes(os, "result", sig.results);
-  }
-  return os << ")";
-}
-
-std::ostream& operator<<(std::ostream& os, Field field) {
-  if (field.mutable_) {
-    os << "(mut ";
-  }
-  if (field.isPacked()) {
-    auto packedType = field.packedType;
-    if (packedType == Field::PackedType::i8) {
-      os << "i8";
-    } else if (packedType == Field::PackedType::i16) {
-      os << "i16";
-    } else {
-      WASM_UNREACHABLE("unexpected packed type");
-    }
-  } else {
-    os << field.type;
-  }
-  if (field.mutable_) {
-    os << ")";
-  }
-  return os;
-};
-
-std::ostream& operator<<(std::ostream& os, Struct struct_) {
-  os << "(struct";
-  if (struct_.fields.size()) {
-    os << " (field";
-    for (auto f : struct_.fields) {
-      os << " " << f;
-    }
-    os << ")";
-  }
-  return os << ")";
-}
-
-std::ostream& operator<<(std::ostream& os, Array array) {
-  return os << "(array " << array.element << ")";
-}
-
-std::ostream& operator<<(std::ostream& os, HeapType heapType) {
-  switch (heapType.kind) {
-    case wasm::HeapType::FuncKind:
-      return os << "func";
-    case wasm::HeapType::ExternKind:
-      return os << "extern";
-    case wasm::HeapType::AnyKind:
-      return os << "any";
-    case wasm::HeapType::EqKind:
-      return os << "eq";
-    case wasm::HeapType::I31Kind:
-      return os << "i31";
-    case wasm::HeapType::ExnKind:
-      return os << "exn";
-    case wasm::HeapType::SignatureKind:
-      return os << heapType.signature;
-    case wasm::HeapType::StructKind:
-      return os << heapType.struct_;
-    case wasm::HeapType::ArrayKind:
-      return os << heapType.array;
-  }
-  WASM_UNREACHABLE("unexpected kind");
-}
-
-std::ostream& operator<<(std::ostream& os, Rtt rtt) {
-  return os << "(rtt " << rtt.depth << " " << rtt.heapType << ")";
-}
-
-std::ostream& operator<<(std::ostream& os, TypeInfo info) {
-  switch (info.kind) {
-    case TypeInfo::TupleKind: {
-      return os << info.tuple;
-    }
-    case TypeInfo::RefKind: {
-      os << "(ref ";
-      if (info.ref.nullable) {
-        os << "null ";
-      }
-      return os << info.ref.heapType << ")";
-    }
-    case TypeInfo::RttKind: {
-      return os << info.rtt;
-    }
-  }
-  WASM_UNREACHABLE("unexpected kind");
-}
-
-} // namespace wasm
+#include <unordered_set>
+
+#include "compiler-support.h"
+#include "support/hash.h"
+#include "wasm-features.h"
+#include "wasm-type.h"
+
+namespace wasm {
+
+namespace {
+
+struct TypeInfo {
+  using type_t = Type;
+  enum Kind {
+    TupleKind,
+    RefKind,
+    RttKind,
+  } kind;
+  struct Ref {
+    HeapType heapType;
+    Nullability nullable;
+  };
+  union {
+    Tuple tuple;
+    Ref ref;
+    Rtt rtt;
+  };
+
+  TypeInfo(const Tuple& tuple) : kind(TupleKind), tuple(tuple) {}
+  TypeInfo(Tuple&& tuple) : kind(TupleKind), tuple(std::move(tuple)) {}
+  TypeInfo(HeapType heapType, Nullability nullable)
+    : kind(RefKind), ref{heapType, nullable} {}
+  TypeInfo(Rtt rtt) : kind(RttKind), rtt(rtt) {}
+  TypeInfo(const TypeInfo& other);
+  ~TypeInfo();
+
+  constexpr bool isTuple() const { return kind == TupleKind; }
+  constexpr bool isRef() const { return kind == RefKind; }
+  constexpr bool isRtt() const { return kind == RttKind; }
+
+  bool isNullable() const { return kind == RefKind && ref.nullable; }
+
+  bool operator==(const TypeInfo& other) const;
+  bool operator!=(const TypeInfo& other) const { return !(*this == other); }
+  bool operator<(const TypeInfo& other) const;
+};
+
+struct HeapTypeInfo {
+  using type_t = HeapType;
+  enum Kind {
+    SignatureKind,
+    StructKind,
+    ArrayKind,
+  } kind;
+  union {
+    Signature signature;
+    Struct struct_;
+    Array array;
+  };
+
+  HeapTypeInfo(Signature sig) : kind(SignatureKind), signature(sig) {}
+  HeapTypeInfo(const Struct& struct_) : kind(StructKind), struct_(struct_) {}
+  HeapTypeInfo(Struct&& struct_)
+    : kind(StructKind), struct_(std::move(struct_)) {}
+  HeapTypeInfo(Array array) : kind(ArrayKind), array(array) {}
+  HeapTypeInfo(const HeapTypeInfo& other);
+  ~HeapTypeInfo();
+
+  constexpr bool isSignature() const { return kind == SignatureKind; }
+  constexpr bool isStruct() const { return kind == StructKind; }
+  constexpr bool isArray() const { return kind == ArrayKind; }
+
+  HeapTypeInfo& operator=(const HeapTypeInfo& other);
+  bool operator==(const HeapTypeInfo& other) const;
+  bool operator!=(const HeapTypeInfo& other) const { return !(*this == other); }
+  bool operator<(const HeapTypeInfo& other) const;
+};
+
+} // anonymous namespace
+} // namespace wasm
+
+namespace std {
+
+template<> class hash<wasm::TypeInfo> {
+public:
+  size_t operator()(const wasm::TypeInfo&) const;
+};
+
+template<> class hash<wasm::HeapTypeInfo> {
+public:
+  size_t operator()(const wasm::HeapTypeInfo&) const;
+};
+
+} // namespace std
+
+namespace wasm {
+namespace {
+
+TypeInfo* getTypeInfo(Type type) {
+  assert(type.isCompound());
+  return (TypeInfo*)type.getID();
+}
+
+HeapTypeInfo* getHeapTypeInfo(HeapType ht) {
+  assert(ht.isCompound());
+  return (HeapTypeInfo*)ht.getID();
+}
+
+TypeInfo::TypeInfo(const TypeInfo& other) {
+  kind = other.kind;
+  switch (kind) {
+    case TupleKind:
+      new (&tuple) auto(other.tuple);
+      return;
+    case RefKind:
+      new (&ref) auto(other.ref);
+      return;
+    case RttKind:
+      new (&rtt) auto(other.rtt);
+      return;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+TypeInfo::~TypeInfo() {
+  switch (kind) {
+    case TupleKind:
+      tuple.~Tuple();
+      return;
+    case RefKind:
+      ref.~Ref();
+      return;
+    case RttKind:
+      rtt.~Rtt();
+      return;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+bool TypeInfo::operator==(const TypeInfo& other) const {
+  if (kind != other.kind) {
+    return false;
+  }
+  switch (kind) {
+    case TupleKind:
+      return tuple == other.tuple;
+    case RefKind:
+      return ref.heapType == other.ref.heapType &&
+             ref.nullable == other.ref.nullable;
+    case RttKind:
+      return rtt == other.rtt;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+bool TypeInfo::operator<(const TypeInfo& other) const {
+  if (kind != other.kind) {
+    return kind < other.kind;
+  }
+  switch (kind) {
+    case TupleKind:
+      return tuple < other.tuple;
+    case RefKind:
+      if (ref.nullable != other.ref.nullable) {
+        return ref.nullable < other.ref.nullable;
+      }
+      return ref.heapType < other.ref.heapType;
+    case RttKind:
+      return rtt < other.rtt;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+HeapTypeInfo::HeapTypeInfo(const HeapTypeInfo& other) {
+  kind = other.kind;
+  switch (kind) {
+    case SignatureKind:
+      new (&signature) auto(other.signature);
+      return;
+    case StructKind:
+      new (&struct_) auto(other.struct_);
+      return;
+    case ArrayKind:
+      new (&array) auto(other.array);
+      return;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+HeapTypeInfo::~HeapTypeInfo() {
+  switch (kind) {
+    case SignatureKind:
+      signature.~Signature();
+      return;
+    case StructKind:
+      struct_.~Struct();
+      return;
+    case ArrayKind:
+      array.~Array();
+      return;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+HeapTypeInfo& HeapTypeInfo::operator=(const HeapTypeInfo& other) {
+  if (&other != this) {
+    this->~HeapTypeInfo();
+    new (this) HeapTypeInfo(other);
+  }
+  return *this;
+}
+
+bool HeapTypeInfo::operator==(const HeapTypeInfo& other) const {
+  if (kind != other.kind) {
+    return false;
+  }
+  switch (kind) {
+    case SignatureKind:
+      return signature == other.signature;
+    case StructKind:
+      return struct_ == other.struct_;
+    case ArrayKind:
+      return array == other.array;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+bool HeapTypeInfo::operator<(const HeapTypeInfo& other) const {
+  if (kind != other.kind) {
+    return kind < other.kind;
+  }
+  switch (kind) {
+    case SignatureKind:
+      return signature < other.signature;
+    case StructKind:
+      return struct_ < other.struct_;
+    case ArrayKind:
+      return array < other.array;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+template<typename Info> struct Store {
+  std::mutex mutex;
+
+  // Track unique_ptrs for constructed types to avoid leaks.
+  std::vector<std::unique_ptr<Info>> constructedTypes;
+
+  // Maps from constructed types to their canonical Type IDs.
+  std::unordered_map<Info, uintptr_t> typeIDs;
+
+  typename Info::type_t canonicalize(const Info& info) {
+    std::lock_guard<std::mutex> lock(mutex);
+    auto indexIt = typeIDs.find(info);
+    if (indexIt != typeIDs.end()) {
+      return typename Info::type_t(indexIt->second);
+    }
+    auto ptr = std::make_unique<Info>(info);
+    auto id = uintptr_t(ptr.get());
+    constructedTypes.push_back(std::move(ptr));
+    assert(id > Info::type_t::_last_basic_type);
+    typeIDs[info] = id;
+    return typename Info::type_t(id);
+  }
+};
+
+struct TypeStore : Store<TypeInfo> {
+  Type canonicalize(TypeInfo info) {
+    if (info.isTuple()) {
+      if (info.tuple.types.size() == 0) {
+        return Type::none;
+      }
+      if (info.tuple.types.size() == 1) {
+        return info.tuple.types[0];
+      }
+    }
+    if (info.isRef() && info.ref.heapType.isBasic()) {
+      if (info.ref.nullable) {
+        switch (info.ref.heapType.getBasic()) {
+          case HeapType::func:
+            return Type::funcref;
+          case HeapType::ext:
+            return Type::externref;
+          case HeapType::exn:
+            return Type::exnref;
+          case HeapType::any:
+            return Type::anyref;
+          case HeapType::eq:
+            return Type::eqref;
+          case HeapType::i31:
+            break;
+        }
+      } else {
+        if (info.ref.heapType == HeapType::i31) {
+          return Type::i31ref;
+        }
+      }
+    }
+    return Store<TypeInfo>::canonicalize(info);
+  }
+};
+
+using HeapTypeStore = Store<HeapTypeInfo>;
+
+TypeStore globalTypeStore;
+HeapTypeStore globalHeapTypeStore;
+
+// Specialized to simplify programming generically over Types and HeapTypes.
+template<typename T> struct MetaTypeInfo {};
+
+template<> struct MetaTypeInfo<Type> {
+  constexpr static TypeStore& globalStore = globalTypeStore;
+  static TypeInfo* getInfo(Type type) { return getTypeInfo(type); }
+};
+
+template<> struct MetaTypeInfo<HeapType> {
+  constexpr static HeapTypeStore& globalStore = globalHeapTypeStore;
+  static HeapTypeInfo* getInfo(HeapType ht) { return getHeapTypeInfo(ht); }
+};
+
+} // anonymous namespace
+
+Type::Type(std::initializer_list<Type> types) : Type(Tuple(types)) {}
+
+Type::Type(const Tuple& tuple) {
+  new (this) Type(globalTypeStore.canonicalize(tuple));
+}
+
+Type::Type(Tuple&& tuple) {
+  new (this) Type(globalTypeStore.canonicalize(std::move(tuple)));
+}
+
+Type::Type(HeapType heapType, Nullability nullable) {
+  new (this) Type(globalTypeStore.canonicalize(TypeInfo(heapType, nullable)));
+}
+
+Type::Type(Rtt rtt) { new (this) Type(globalTypeStore.canonicalize(rtt)); }
+
+bool Type::isTuple() const {
+  if (isBasic()) {
+    return false;
+  } else {
+    return getTypeInfo(*this)->isTuple();
+  }
+}
+
+bool Type::isRef() const {
+  if (isBasic()) {
+    return id >= funcref && id <= i31ref;
+  } else {
+    return getTypeInfo(*this)->isRef();
+  }
+}
+
+bool Type::isFunction() const {
+  if (isBasic()) {
+    return id == funcref;
+  } else {
+    auto* info = getTypeInfo(*this);
+    return info->isRef() && info->ref.heapType.isFunction();
+  }
+}
+
+bool Type::isException() const {
+  if (isBasic()) {
+    return id == exnref;
+  } else {
+    auto* info = getTypeInfo(*this);
+    return info->isRef() && info->ref.heapType == HeapType::exn;
+  }
+}
+
+bool Type::isNullable() const {
+  if (isBasic()) {
+    return id >= funcref && id <= eqref; // except i31ref
+  } else {
+    return getTypeInfo(*this)->isNullable();
+  }
+}
+
+bool Type::isRtt() const {
+  if (isBasic()) {
+    return false;
+  } else {
+    return getTypeInfo(*this)->isRtt();
+  }
+}
+
+bool Type::isStruct() const { return isRef() && getHeapType().isStruct(); }
+
+bool Type::isArray() const { return isRef() && getHeapType().isArray(); }
+
+bool Type::operator<(const Type& other) const {
+  if (*this == other) {
+    return false;
+  }
+  if (isBasic() && other.isBasic()) {
+    return getBasic() < other.getBasic();
+  }
+  if (isBasic()) {
+    return true;
+  }
+  if (other.isBasic()) {
+    return false;
+  }
+  return *getTypeInfo(*this) < *getTypeInfo(other);
+};
+
+unsigned Type::getByteSize() const {
+  // TODO: alignment?
+  auto getSingleByteSize = [](Type t) {
+    switch (t.getBasic()) {
+      case Type::i32:
+      case Type::f32:
+        return 4;
+      case Type::i64:
+      case Type::f64:
+        return 8;
+      case Type::v128:
+        return 16;
+      case Type::funcref:
+      case Type::externref:
+      case Type::exnref:
+      case Type::anyref:
+      case Type::eqref:
+      case Type::i31ref:
+      case Type::none:
+      case Type::unreachable:
+        break;
+    }
+    WASM_UNREACHABLE("invalid type");
+  };
+
+  if (isTuple()) {
+    unsigned size = 0;
+    for (const auto& t : *this) {
+      size += getSingleByteSize(t);
+    }
+    return size;
+  }
+  return getSingleByteSize(*this);
+}
+
+Type Type::reinterpret() const {
+  assert(!isTuple() && "Unexpected tuple type");
+  switch ((*begin()).getBasic()) {
+    case Type::i32:
+      return f32;
+    case Type::i64:
+      return f64;
+    case Type::f32:
+      return i32;
+    case Type::f64:
+      return i64;
+    default:
+      WASM_UNREACHABLE("invalid type");
+  }
+}
+
+FeatureSet Type::getFeatures() const {
+  auto getSingleFeatures = [](Type t) -> FeatureSet {
+    if (t.isRef()) {
+      // A reference type implies we need that feature. Some also require more,
+      // such as GC or exceptions.
+      auto heapType = t.getHeapType();
+      if (heapType.isStruct() || heapType.isArray()) {
+        return FeatureSet::ReferenceTypes | FeatureSet::GC;
+      }
+      if (heapType.isBasic()) {
+        switch (heapType.getBasic()) {
+          case HeapType::BasicHeapType::exn:
+            return FeatureSet::ReferenceTypes | FeatureSet::ExceptionHandling;
+          case HeapType::BasicHeapType::any:
+          case HeapType::BasicHeapType::eq:
+          case HeapType::BasicHeapType::i31:
+            return FeatureSet::ReferenceTypes | FeatureSet::GC;
+          default: {}
+        }
+      }
+      // Note: Technically typed function references also require the typed
+      // function references feature, however, we use these types internally
+      // regardless of the presence of features (in particular, since during
+      // load of the wasm we don't know the features yet, so we apply the more
+      // refined types), so we don't add that in any case here.
+      return FeatureSet::ReferenceTypes;
+    } else if (t.isRtt()) {
+      return FeatureSet::ReferenceTypes | FeatureSet::GC;
+    }
+    TODO_SINGLE_COMPOUND(t);
+    switch (t.getBasic()) {
+      case Type::v128:
+        return FeatureSet::SIMD;
+      default:
+        return FeatureSet::MVP;
+    }
+  };
+
+  if (isTuple()) {
+    FeatureSet feats = FeatureSet::Multivalue;
+    for (const auto& t : *this) {
+      feats |= getSingleFeatures(t);
+    }
+    return feats;
+  }
+  return getSingleFeatures(*this);
+}
+
+HeapType Type::getHeapType() const {
+  if (isBasic()) {
+    switch (getBasic()) {
+      case Type::none:
+      case Type::unreachable:
+      case Type::i32:
+      case Type::i64:
+      case Type::f32:
+      case Type::f64:
+      case Type::v128:
+        break;
+      case Type::funcref:
+        return HeapType::func;
+      case Type::externref:
+        return HeapType::ext;
+      case Type::exnref:
+        return HeapType::exn;
+      case Type::anyref:
+        return HeapType::any;
+      case Type::eqref:
+        return HeapType::eq;
+      case Type::i31ref:
+        return HeapType::i31;
+    }
+    WASM_UNREACHABLE("Unexpected type");
+  } else {
+    auto* info = getTypeInfo(*this);
+    switch (info->kind) {
+      case TypeInfo::TupleKind:
+        break;
+      case TypeInfo::RefKind:
+        return info->ref.heapType;
+      case TypeInfo::RttKind:
+        return info->rtt.heapType;
+    }
+    WASM_UNREACHABLE("Unexpected type");
+  }
+}
+
+Rtt Type::getRtt() const {
+  assert(isRtt());
+  return getTypeInfo(*this)->rtt;
+}
+
+Type Type::get(unsigned byteSize, bool float_) {
+  if (byteSize < 4) {
+    return Type::i32;
+  }
+  if (byteSize == 4) {
+    return float_ ? Type::f32 : Type::i32;
+  }
+  if (byteSize == 8) {
+    return float_ ? Type::f64 : Type::i64;
+  }
+  if (byteSize == 16) {
+    return Type::v128;
+  }
+  WASM_UNREACHABLE("invalid size");
+}
+
+bool Type::isSubType(Type left, Type right) {
+  if (left == right) {
+    return true;
+  }
+  if (left.isRef() && right.isRef()) {
+    // Everything is a subtype of anyref.
+    if (right == Type::anyref) {
+      return true;
+    }
+    // Various things are subtypes of eqref.
+    auto leftHeap = left.getHeapType();
+    auto rightHeap = right.getHeapType();
+    if ((leftHeap == HeapType::i31 || leftHeap.isArray() ||
+         leftHeap.isStruct()) &&
+        rightHeap == HeapType::eq &&
+        (!left.isNullable() || right.isNullable())) {
+      return true;
+    }
+    // All typed function signatures are subtypes of funcref.
+    if (leftHeap.isSignature() && rightHeap == HeapType::func &&
+        (!left.isNullable() || right.isNullable())) {
+      return true;
+    }
+    // A non-nullable type is a supertype of a nullable one
+    if (leftHeap == rightHeap && !left.isNullable()) {
+      // The only difference is the nullability.
+      assert(right.isNullable());
+      return true;
+    }
+    return false;
+  }
+  if (left.isTuple() && right.isTuple()) {
+    if (left.size() != right.size()) {
+      return false;
+    }
+    for (size_t i = 0; i < left.size(); ++i) {
+      if (!isSubType(left[i], right[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+  if (left.isRtt() && right.isRtt()) {
+    auto leftRtt = left.getRtt();
+    auto rightRtt = right.getRtt();
+    // (rtt n $x) is a subtype of (rtt $x), that is, if the only difference in
+    // information is that the left side specifies a depth while the right side
+    // allows any depth.
+    return leftRtt.heapType == rightRtt.heapType && leftRtt.hasDepth() &&
+           !rightRtt.hasDepth();
+  }
+  return false;
+}
+
+Type Type::getLeastUpperBound(Type a, Type b) {
+  if (a == b) {
+    return a;
+  }
+  if (a == Type::unreachable) {
+    return b;
+  }
+  if (b == Type::unreachable) {
+    return a;
+  }
+  if (a.size() != b.size()) {
+    return Type::none; // a poison value that must not be consumed
+  }
+  if (a.isRef()) {
+    if (b.isRef()) {
+      if (a.isFunction() && b.isFunction()) {
+        return Type::funcref;
+      }
+      if ((a == Type::i31ref && b == Type::eqref) ||
+          (a == Type::eqref && b == Type::i31ref)) {
+        return Type::eqref;
+      }
+      // The LUB of two different reference types is anyref, which may or may
+      // not be a valid type depending on whether the anyref feature is enabled.
+      // When anyref is disabled, it is possible for the finalization of invalid
+      // code to introduce a use of anyref via this function, but that is not a
+      // problem because it will be caught and rejected by validation.
+      return Type::anyref;
+    }
+    return Type::none;
+  }
+  if (a.isTuple()) {
+    TypeList types;
+    types.resize(a.size());
+    for (size_t i = 0; i < types.size(); ++i) {
+      types[i] = getLeastUpperBound(a[i], b[i]);
+      if (types[i] == Type::none) {
+        return Type::none;
+      }
+    }
+    return Type(types);
+  }
+  return Type::none;
+}
+
+Type::Iterator Type::end() const {
+  if (isTuple()) {
+    return Iterator(this, getTypeInfo(*this)->tuple.types.size());
+  } else {
+    // TODO: unreachable is special and expands to {unreachable} currently.
+    // see also: https://github.com/WebAssembly/binaryen/issues/3062
+    return Iterator(this, size_t(id != Type::none));
+  }
+}
+
+const Type& Type::Iterator::operator*() const {
+  if (parent->isTuple()) {
+    return getTypeInfo(*parent)->tuple.types[index];
+  } else {
+    // TODO: see comment in Type::end()
+    assert(index == 0 && parent->id != Type::none && "Index out of bounds");
+    return *parent;
+  }
+}
+
+const Type& Type::operator[](size_t index) const {
+  if (isTuple()) {
+    return getTypeInfo(*this)->tuple.types[index];
+  } else {
+    assert(index == 0 && "Index out of bounds");
+    return *begin();
+  }
+}
+
+HeapType::HeapType(Signature signature) {
+  new (this) HeapType(globalHeapTypeStore.canonicalize(signature));
+}
+
+HeapType::HeapType(const Struct& struct_) {
+  new (this) HeapType(globalHeapTypeStore.canonicalize(struct_));
+}
+
+HeapType::HeapType(Struct&& struct_) {
+  new (this) HeapType(globalHeapTypeStore.canonicalize(std::move(struct_)));
+}
+
+HeapType::HeapType(Array array) {
+  new (this) HeapType(globalHeapTypeStore.canonicalize(array));
+}
+
+bool HeapType::isFunction() const {
+  if (isBasic()) {
+    return id == func;
+  } else {
+    return getHeapTypeInfo(*this)->isSignature();
+  }
+}
+
+bool HeapType::isSignature() const {
+  if (isBasic()) {
+    return false;
+  } else {
+    return getHeapTypeInfo(*this)->isSignature();
+  }
+}
+
+bool HeapType::isStruct() const {
+  if (isBasic()) {
+    return false;
+  } else {
+    return getHeapTypeInfo(*this)->isStruct();
+  }
+}
+
+bool HeapType::operator<(const HeapType& other) const {
+  if (*this == other) {
+    return false;
+  }
+  if (isBasic() && other.isBasic()) {
+    return getBasic() < other.getBasic();
+  }
+  if (isBasic()) {
+    return true;
+  }
+  if (other.isBasic()) {
+    return false;
+  }
+  return *getHeapTypeInfo(*this) < *getHeapTypeInfo(other);
+}
+
+bool HeapType::isArray() const {
+  if (isBasic()) {
+    return false;
+  } else {
+    return getHeapTypeInfo(*this)->isArray();
+  }
+}
+
+Signature HeapType::getSignature() const {
+  assert(isSignature());
+  return getHeapTypeInfo(*this)->signature;
+}
+
+const Struct& HeapType::getStruct() const {
+  assert(isStruct());
+  return getHeapTypeInfo(*this)->struct_;
+}
+
+Array HeapType::getArray() const {
+  assert(isArray());
+  return getHeapTypeInfo(*this)->array;
+}
+
+bool Signature::operator<(const Signature& other) const {
+  if (results != other.results) {
+    return results < other.results;
+  }
+  return params < other.params;
+}
+
+bool Field::operator<(const Field& other) const {
+  if (mutable_ != other.mutable_) {
+    return mutable_ < other.mutable_;
+  }
+  if (type == Type::i32 && other.type == Type::i32) {
+    return packedType < other.packedType;
+  }
+  return type < other.type;
+}
+
+bool Rtt::operator<(const Rtt& other) const {
+  if (depth != other.depth) {
+    return depth < other.depth;
+  }
+  return heapType < other.heapType;
+}
+
+namespace {
+
+std::ostream&
+printPrefixedTypes(std::ostream& os, const char* prefix, Type type) {
+  os << '(' << prefix;
+  for (const auto& t : type) {
+    os << " " << t;
+  }
+  os << ')';
+  return os;
+}
+
+template<typename T> std::string genericToString(const T& t) {
+  std::ostringstream ss;
+  ss << t;
+  return ss.str();
+}
+
+} // anonymous namespace
+
+std::string Type::toString() const { return genericToString(*this); }
+
+std::string ParamType::toString() const { return genericToString(*this); }
+
+std::string ResultType::toString() const { return genericToString(*this); }
+
+std::string Tuple::toString() const { return genericToString(*this); }
+
+std::string Signature::toString() const { return genericToString(*this); }
+
+std::string Struct::toString() const { return genericToString(*this); }
+
+std::string Array::toString() const { return genericToString(*this); }
+
+std::string HeapType::toString() const { return genericToString(*this); }
+
+std::string Rtt::toString() const { return genericToString(*this); }
+
+std::ostream& operator<<(std::ostream&, TypeInfo);
+std::ostream& operator<<(std::ostream&, HeapTypeInfo);
+
+std::ostream& operator<<(std::ostream& os, Type type) {
+  if (type.isBasic()) {
+    switch (type.getBasic()) {
+      case Type::none:
+        return os << "none";
+      case Type::unreachable:
+        return os << "unreachable";
+      case Type::i32:
+        return os << "i32";
+      case Type::i64:
+        return os << "i64";
+      case Type::f32:
+        return os << "f32";
+      case Type::f64:
+        return os << "f64";
+      case Type::v128:
+        return os << "v128";
+      case Type::funcref:
+        return os << "funcref";
+      case Type::externref:
+        return os << "externref";
+      case Type::exnref:
+        return os << "exnref";
+      case Type::anyref:
+        return os << "anyref";
+      case Type::eqref:
+        return os << "eqref";
+      case Type::i31ref:
+        return os << "i31ref";
+    }
+  }
+  return os << *getTypeInfo(type);
+}
+
+std::ostream& operator<<(std::ostream& os, ParamType param) {
+  return printPrefixedTypes(os, "param", param.type);
+}
+
+std::ostream& operator<<(std::ostream& os, ResultType param) {
+  return printPrefixedTypes(os, "result", param.type);
+}
+
+std::ostream& operator<<(std::ostream& os, Tuple tuple) {
+  auto& types = tuple.types;
+  auto size = types.size();
+  os << "(";
+  if (size) {
+    os << types[0];
+    for (size_t i = 1; i < size; ++i) {
+      os << " " << types[i];
+    }
+  }
+  return os << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, Signature sig) {
+  os << "(func";
+  if (sig.params.getID() != Type::none) {
+    os << " ";
+    printPrefixedTypes(os, "param", sig.params);
+  }
+  if (sig.results.getID() != Type::none) {
+    os << " ";
+    printPrefixedTypes(os, "result", sig.results);
+  }
+  return os << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, Field field) {
+  if (field.mutable_) {
+    os << "(mut ";
+  }
+  if (field.isPacked()) {
+    auto packedType = field.packedType;
+    if (packedType == Field::PackedType::i8) {
+      os << "i8";
+    } else if (packedType == Field::PackedType::i16) {
+      os << "i16";
+    } else {
+      WASM_UNREACHABLE("unexpected packed type");
+    }
+  } else {
+    os << field.type;
+  }
+  if (field.mutable_) {
+    os << ")";
+  }
+  return os;
+};
+
+std::ostream& operator<<(std::ostream& os, Struct struct_) {
+  os << "(struct";
+  if (struct_.fields.size()) {
+    os << " (field";
+    for (auto f : struct_.fields) {
+      os << " " << f;
+    }
+    os << ")";
+  }
+  return os << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, Array array) {
+  return os << "(array " << array.element << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, HeapType heapType) {
+  if (heapType.isBasic()) {
+    switch (heapType.getBasic()) {
+      case HeapType::func:
+        return os << "func";
+      case HeapType::ext:
+        return os << "extern";
+      case HeapType::exn:
+        return os << "exn";
+      case HeapType::any:
+        return os << "any";
+      case HeapType::eq:
+        return os << "eq";
+      case HeapType::i31:
+        return os << "i31";
+    }
+  }
+  return os << *getHeapTypeInfo(heapType);
+}
+
+std::ostream& operator<<(std::ostream& os, Rtt rtt) {
+  return os << "(rtt " << rtt.depth << " " << rtt.heapType << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, TypeInfo info) {
+  switch (info.kind) {
+    case TypeInfo::TupleKind: {
+      return os << info.tuple;
+    }
+    case TypeInfo::RefKind: {
+      os << "(ref ";
+      if (info.ref.nullable) {
+        os << "null ";
+      }
+      return os << info.ref.heapType << ")";
+    }
+    case TypeInfo::RttKind: {
+      return os << info.rtt;
+    }
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+std::ostream& operator<<(std::ostream& os, HeapTypeInfo info) {
+  switch (info.kind) {
+    case HeapTypeInfo::SignatureKind:
+      return os << info.signature;
+    case HeapTypeInfo::StructKind:
+      return os << info.struct_;
+    case HeapTypeInfo::ArrayKind:
+      return os << info.array;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+struct TypeBuilder::Impl {
+  TypeStore typeStore;
+  HeapTypeStore heapTypeStore;
+
+  struct Entry {
+    // HeapTypeInfo has no default constructor, so pick an arbitrary default.
+    HeapTypeInfo info = Signature();
+    bool initialized = false;
+    void set(HeapTypeInfo&& hti) {
+      info = hti;
+      initialized = true;
+    }
+    HeapType get() { return HeapType(TypeID(&info)); }
+  };
+
+  std::vector<Entry> entries;
+};
+
+TypeBuilder::TypeBuilder(size_t n) {
+  impl = std::make_unique<TypeBuilder::Impl>();
+  impl->entries.resize(n);
+}
+
+TypeBuilder::~TypeBuilder() = default;
+
+void TypeBuilder::setHeapType(size_t i, Signature signature) {
+  assert(i < impl->entries.size() && "Index out of bounds");
+  impl->entries[i].set(signature);
+}
+
+void TypeBuilder::setHeapType(size_t i, const Struct& struct_) {
+  assert(i < impl->entries.size() && "index out of bounds");
+  impl->entries[i].set(struct_);
+}
+
+void TypeBuilder::setHeapType(size_t i, Struct&& struct_) {
+  assert(i < impl->entries.size() && "index out of bounds");
+  impl->entries[i].set(std::move(struct_));
+}
+
+void TypeBuilder::setHeapType(size_t i, Array array) {
+  assert(i < impl->entries.size() && "index out of bounds");
+  impl->entries[i].set(array);
+}
+
+Type TypeBuilder::getTempTupleType(const Tuple& tuple) {
+  return impl->typeStore.canonicalize(tuple);
+}
+
+Type TypeBuilder::getTempRefType(size_t i, Nullability nullable) {
+  assert(i < impl->entries.size() && "Index out of bounds");
+  return impl->typeStore.canonicalize(
+    TypeInfo(impl->entries[i].get(), nullable));
+}
+
+Type TypeBuilder::getTempRttType(size_t i, uint32_t depth) {
+  assert(i < impl->entries.size() && "Index out of bounds");
+  return impl->typeStore.canonicalize(Rtt(depth, impl->entries[i].get()));
+}
+
+namespace {
+
+// Implements the algorithm to canonicalize the HeapTypes in a TypeBuilder,
+// replacing and deduplicating the temporary type and heaptypes backed by
+// storage owned by the TypeBuilder into normal types and heap types backed by
+// the global stores.
+struct Canonicalizer {
+  TypeBuilder& builder;
+
+  struct Item {
+    enum Kind {
+      TypeKind,
+      HeapTypeKind,
+    } kind;
+    union {
+      Type* type;
+      HeapType* heapType;
+    };
+    Item(Type* type) : kind(TypeKind), type(type) {}
+    Item(HeapType* heapType) : kind(HeapTypeKind), heapType(heapType) {}
+  };
+
+  // IDs of scanned Types and HeapTypes, used to prevent repeated scanning.
+  std::unordered_set<TypeID> scanned;
+
+  // The work list of Types and HeapTypes remaining to be scanned.
+  std::vector<Item> scanList;
+
+  // The list of Types and HeapTypes to visit constructed in forward preorder
+  // and eventually traversed in reverse to give a reverse postorder.
+  std::vector<Item> visitList;
+
+  // Maps Type and HeapType IDs to the IDs of Types and HeapTypes they can
+  // reach in the type graph. Only considers compound Types and HeapTypes.
+  std::unordered_map<TypeID, std::unordered_set<TypeID>> reaches;
+
+  // Maps Types and HeapTypes backed by the TypeBuilder's Stores to globally
+  // canonical Types and HeapTypes.
+  std::unordered_map<Type, Type> canonicalTypes;
+  std::unordered_map<HeapType, HeapType> canonicalHeapTypes;
+
+  // The fully canonicalized heap types.
+  std::vector<HeapType> results;
+
+  Canonicalizer(TypeBuilder& builder);
+  template<typename T1, typename T2> void noteChild(T1 parent, T2* child);
+  void scanHeapType(HeapType* ht);
+  void scanType(Type* child);
+  void makeReachabilityFixedPoint();
+
+  // Replaces the pointee Type or HeapType of `type` with its globally canonical
+  // equivalent, recording the substitution for future use in either
+  // `canonicalTypes` or `canonicalHeapTypes`.
+  template<typename T>
+  void canonicalize(T* type, std::unordered_map<T, T>& canonicals);
+};
+
+// Traverse the type graph rooted at the initialized HeapTypeInfos in reverse
+// postorder, replacing in place all Types and HeapTypes backed by the
+// TypeBuilder's Stores with equivalent globally canonicalized Types and
+// HeapTypes.
+Canonicalizer::Canonicalizer(TypeBuilder& builder) : builder(builder) {
+  // Initialize `results` to hold all the temporary HeapTypes. Since we are
+  // canonicalizing all Types and HeapTypes in place, this will end up holding
+  // all the canonicalized HeapTypes instead. Also seed the scan list with these
+  // HeapTypes.
+  results.reserve(builder.impl->entries.size());
+  for (auto& entry : builder.impl->entries) {
+    assert(entry.initialized && "Cannot access uninitialized HeapType");
+    results.push_back(entry.get());
+    scanList.push_back(&results.back());
+  }
+
+  // Traverse the type graph reachable from the heap types, calculating
+  // reachability and collecting a list of types and heap types that need to be
+  // canonicalized. We must scan in depth-first order so that we can do a
+  // postorder traversal later.
+  while (scanList.size() != 0) {
+    auto item = scanList.back();
+    scanList.pop_back();
+    switch (item.kind) {
+      case Item::TypeKind:
+        scanType(item.type);
+        break;
+      case Item::HeapTypeKind:
+        scanHeapType(item.heapType);
+        break;
+    }
+  }
+
+  // Check for recursive types and heap types. TODO: pre-canonicalize these into
+  // their minimal finite representations.
+  makeReachabilityFixedPoint();
+  for (auto& reach : reaches) {
+    if (reach.second.count(reach.first) != 0) {
+      WASM_UNREACHABLE("TODO: support recursive types");
+    }
+  }
+
+  // Visit the types and heap types in reverse postorder, replacing them with
+  // their canonicalized versions.
+  for (auto it = visitList.rbegin(); it != visitList.rend(); ++it) {
+    switch (it->kind) {
+      case Item::TypeKind:
+        canonicalize(it->type, canonicalTypes);
+        break;
+      case Item::HeapTypeKind:
+        canonicalize(it->heapType, canonicalHeapTypes);
+        break;
+    }
+  }
+}
+
+template<typename T1, typename T2>
+void Canonicalizer::noteChild(T1 parent, T2* child) {
+  if (child->isCompound()) {
+    reaches[parent.getID()].insert(child->getID());
+    scanList.push_back(child);
+  }
+}
+
+void Canonicalizer::scanHeapType(HeapType* ht) {
+  assert(ht->isCompound());
+  visitList.push_back(ht);
+  if (scanned.count(ht->getID())) {
+    return;
+  }
+  scanned.insert(ht->getID());
+
+  auto* info = getHeapTypeInfo(*ht);
+  switch (info->kind) {
+    case HeapTypeInfo::SignatureKind:
+      noteChild(*ht, &info->signature.params);
+      noteChild(*ht, &info->signature.results);
+      break;
+    case HeapTypeInfo::StructKind:
+      for (auto& field : info->struct_.fields) {
+        noteChild(*ht, &field.type);
+      }
+      break;
+    case HeapTypeInfo::ArrayKind:
+      noteChild(*ht, &info->array.element.type);
+      break;
+  }
+};
+
+void Canonicalizer::scanType(Type* type) {
+  assert(type->isCompound());
+  visitList.push_back(type);
+  if (scanned.count(type->getID())) {
+    return;
+  }
+  scanned.insert(type->getID());
+
+  auto* info = getTypeInfo(*type);
+  switch (info->kind) {
+    case TypeInfo::TupleKind:
+      for (auto& child : info->tuple.types) {
+        noteChild(*type, &child);
+      }
+      break;
+    case TypeInfo::RefKind:
+      noteChild(*type, &info->ref.heapType);
+      break;
+    case TypeInfo::RttKind:
+      noteChild(*type, &info->rtt.heapType);
+      break;
+  }
+}
+
+void Canonicalizer::makeReachabilityFixedPoint() {
+  // Naively calculate the transitive closure of the reachability graph.
+  bool changed;
+  do {
+    changed = false;
+    for (auto& entry : reaches) {
+      auto& reachable = entry.second;
+      std::unordered_set<TypeID> nextReachable;
+      for (auto& other : reachable) {
+        auto& otherReaches = reaches[other];
+        nextReachable.insert(otherReaches.begin(), otherReaches.end());
+      }
+      size_t oldSize = reachable.size();
+      reachable.insert(nextReachable.begin(), nextReachable.end());
+      if (reachable.size() != oldSize) {
+        changed = true;
+      }
+    }
+  } while (changed);
+}
+
+template<typename T>
+void Canonicalizer::canonicalize(T* type,
+                                 std::unordered_map<T, T>& canonicals) {
+  auto it = canonicals.find(*type);
+  if (it != canonicals.end()) {
+    *type = it->second;
+  } else {
+    // Get the globally canonicalized version of the type
+    auto* info = MetaTypeInfo<T>::getInfo(*type);
+    T canonical = MetaTypeInfo<T>::globalStore.canonicalize(*info);
+    canonicals.insert({*type, canonical});
+    *type = canonical;
+  }
+}
+
+} // anonymous namespace
+
+std::vector<HeapType> TypeBuilder::build() {
+  return Canonicalizer(*this).results;
+}
+
+} // namespace wasm
+
+namespace std {
+
+template<> class hash<wasm::TypeList> {
+public:
+  size_t operator()(const wasm::TypeList& types) const {
+    auto digest = wasm::hash(types.size());
+    for (auto type : types) {
+      wasm::rehash(digest, type);
+    }
+    return digest;
+  }
+};
+
+template<> class hash<wasm::FieldList> {
+public:
+  size_t operator()(const wasm::FieldList& fields) const {
+    auto digest = wasm::hash(fields.size());
+    for (auto field : fields) {
+      wasm::rehash(digest, field);
+    }
+    return digest;
+  }
+};
+
+size_t hash<wasm::TypeInfo>::operator()(const wasm::TypeInfo& info) const {
+  auto digest = wasm::hash(info.kind);
+  switch (info.kind) {
+    case wasm::TypeInfo::TupleKind:
+      wasm::rehash(digest, info.tuple);
+      return digest;
+    case wasm::TypeInfo::RefKind:
+      wasm::rehash(digest, info.ref.heapType);
+      wasm::rehash(digest, info.ref.nullable);
+      return digest;
+    case wasm::TypeInfo::RttKind:
+      wasm::rehash(digest, info.rtt);
+      return digest;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+size_t hash<wasm::HeapTypeInfo>::
+operator()(const wasm::HeapTypeInfo& info) const {
+  auto digest = wasm::hash(info.kind);
+  switch (info.kind) {
+    case wasm::HeapTypeInfo::SignatureKind:
+      wasm::rehash(digest, info.signature);
+      return digest;
+    case wasm::HeapTypeInfo::StructKind:
+      wasm::rehash(digest, info.struct_);
+      return digest;
+    case wasm::HeapTypeInfo::ArrayKind:
+      wasm::rehash(digest, info.array);
+      return digest;
+  }
+  WASM_UNREACHABLE("unexpected kind");
+}
+
+size_t hash<wasm::Type>::operator()(const wasm::Type& type) const {
+  return wasm::hash(type.getID());
+}
+
+size_t hash<wasm::Tuple>::operator()(const wasm::Tuple& tuple) const {
+  return wasm::hash(tuple.types);
+}
+
+size_t hash<wasm::Signature>::operator()(const wasm::Signature& sig) const {
+  auto digest = wasm::hash(sig.params);
+  wasm::rehash(digest, sig.results);
+  return digest;
+}
+
+size_t hash<wasm::Field>::operator()(const wasm::Field& field) const {
+  auto digest = wasm::hash(field.type);
+  wasm::rehash(digest, field.packedType);
+  wasm::rehash(digest, field.mutable_);
+  // Note that the name is not hashed here - it is pure metadata for printing
+  // purposes only.
+  return digest;
+}
+
+size_t hash<wasm::Struct>::operator()(const wasm::Struct& struct_) const {
+  return wasm::hash(struct_.fields);
+}
+
+size_t hash<wasm::Array>::operator()(const wasm::Array& array) const {
+  return wasm::hash(array.element);
+}
+
+size_t hash<wasm::HeapType>::operator()(const wasm::HeapType& heapType) const {
+  return wasm::hash(heapType.getID());
+}
+
+size_t hash<wasm::Rtt>::operator()(const wasm::Rtt& rtt) const {
+  auto digest = wasm::hash(rtt.depth);
+  wasm::rehash(digest, rtt.heapType);
+  return digest;
+}
+
+} // namespace std
diff --git a/binaryen/src/wasm/wasm-validator.cpp b/binaryen/src/wasm/wasm-validator.cpp
--- a/binaryen/src/wasm/wasm-validator.cpp
+++ b/binaryen/src/wasm/wasm-validator.cpp
@@ -25,7 +25,6 @@
 #include "ir/stack-utils.h"
 #include "ir/utils.h"
 #include "support/colors.h"
-#include "wasm-printing.h"
 #include "wasm-validator.h"
 #include "wasm.h"
 
@@ -41,10 +40,12 @@
   return stream;
 }
 
-// Extra overload for Expressions, to print type info too
+// Extra overload for Expressions, to print their contents.
 inline std::ostream& printModuleComponent(Expression* curr,
                                           std::ostream& stream) {
-  WasmPrinter::printExpression(curr, stream, false, true) << std::endl;
+  if (curr) {
+    stream << *curr << '\n';
+  }
   return stream;
 }
 
@@ -317,6 +318,7 @@
   void visitSIMDTernary(SIMDTernary* curr);
   void visitSIMDShift(SIMDShift* curr);
   void visitSIMDLoad(SIMDLoad* curr);
+  void visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr);
   void visitMemoryInit(MemoryInit* curr);
   void visitDataDrop(DataDrop* curr);
   void visitMemoryCopy(MemoryCopy* curr);
@@ -338,6 +340,7 @@
   void visitBrOnExn(BrOnExn* curr);
   void visitTupleMake(TupleMake* curr);
   void visitTupleExtract(TupleExtract* curr);
+  void visitCallRef(CallRef* curr);
   void visitI31New(I31New* curr);
   void visitI31Get(I31Get* curr);
   void visitRefTest(RefTest* curr);
@@ -405,6 +408,49 @@
     size_t align, Type type, Index bytes, bool isAtomic, Expression* curr);
   void validateMemBytes(uint8_t bytes, Type type, Expression* curr);
 
+  template<typename T> void validateReturnCall(T* curr) {
+    shouldBeTrue(!curr->isReturn || getModule()->features.hasTailCall(),
+                 curr,
+                 "return_call* requires tail calls to be enabled");
+  }
+
+  template<typename T>
+  void validateCallParamsAndResult(T* curr, Signature sig) {
+    if (!shouldBeTrue(curr->operands.size() == sig.params.size(),
+                      curr,
+                      "call* param number must match")) {
+      return;
+    }
+    size_t i = 0;
+    for (const auto& param : sig.params) {
+      if (!shouldBeSubTypeOrFirstIsUnreachable(curr->operands[i]->type,
+                                               param,
+                                               curr,
+                                               "call param types must match") &&
+          !info.quiet) {
+        getStream() << "(on argument " << i << ")\n";
+      }
+      ++i;
+    }
+    if (curr->isReturn) {
+      shouldBeEqual(curr->type,
+                    Type(Type::unreachable),
+                    curr,
+                    "return_call* should have unreachable type");
+      shouldBeEqual(
+        getFunction()->sig.results,
+        sig.results,
+        curr,
+        "return_call* callee return type must match caller return type");
+    } else {
+      shouldBeEqualOrFirstIsUnreachable(
+        curr->type,
+        sig.results,
+        curr,
+        "call* type must match callee return type");
+    }
+  }
+
   Type indexType() { return getModule()->memory.indexType; }
 };
 
@@ -747,9 +793,7 @@
 }
 
 void FunctionValidator::visitCall(Call* curr) {
-  shouldBeTrue(!curr->isReturn || getModule()->features.hasTailCall(),
-               curr,
-               "return_call requires tail calls to be enabled");
+  validateReturnCall(curr);
   if (!info.validateGlobally) {
     return;
   }
@@ -757,107 +801,16 @@
   if (!shouldBeTrue(!!target, curr, "call target must exist")) {
     return;
   }
-  if (!shouldBeTrue(curr->operands.size() == target->sig.params.size(),
-                    curr,
-                    "call param number must match")) {
-    return;
-  }
-  size_t i = 0;
-  for (const auto& param : target->sig.params) {
-    if (!shouldBeSubTypeOrFirstIsUnreachable(curr->operands[i]->type,
-                                             param,
-                                             curr,
-                                             "call param types must match") &&
-        !info.quiet) {
-      getStream() << "(on argument " << i << ")\n";
-    }
-    ++i;
-  }
-  if (curr->isReturn) {
-    shouldBeEqual(curr->type,
-                  Type(Type::unreachable),
-                  curr,
-                  "return_call should have unreachable type");
-    shouldBeEqual(
-      getFunction()->sig.results,
-      target->sig.results,
-      curr,
-      "return_call callee return type must match caller return type");
-  } else {
-    if (curr->type == Type::unreachable) {
-      bool hasUnreachableOperand = std::any_of(
-        curr->operands.begin(), curr->operands.end(), [](Expression* op) {
-          return op->type == Type::unreachable;
-        });
-      shouldBeTrue(
-        hasUnreachableOperand,
-        curr,
-        "calls may only be unreachable if they have unreachable operands");
-    } else {
-      shouldBeEqual(curr->type,
-                    target->sig.results,
-                    curr,
-                    "call type must match callee return type");
-    }
-  }
+  validateCallParamsAndResult(curr, target->sig);
 }
 
 void FunctionValidator::visitCallIndirect(CallIndirect* curr) {
-  shouldBeTrue(!curr->isReturn || getModule()->features.hasTailCall(),
-               curr,
-               "return_call_indirect requires tail calls to be enabled");
-  if (!info.validateGlobally) {
-    return;
-  }
+  validateReturnCall(curr);
   shouldBeEqualOrFirstIsUnreachable(curr->target->type,
                                     Type(Type::i32),
                                     curr,
                                     "indirect call target must be an i32");
-  if (!shouldBeTrue(curr->operands.size() == curr->sig.params.size(),
-                    curr,
-                    "call param number must match")) {
-    return;
-  }
-  size_t i = 0;
-  for (const auto& param : curr->sig.params) {
-    if (!shouldBeSubTypeOrFirstIsUnreachable(curr->operands[i]->type,
-                                             param,
-                                             curr,
-                                             "call param types must match") &&
-        !info.quiet) {
-      getStream() << "(on argument " << i << ")\n";
-    }
-    ++i;
-  }
-  if (curr->isReturn) {
-    shouldBeEqual(curr->type,
-                  Type(Type::unreachable),
-                  curr,
-                  "return_call_indirect should have unreachable type");
-    shouldBeEqual(
-      getFunction()->sig.results,
-      curr->sig.results,
-      curr,
-      "return_call_indirect callee return type must match caller return type");
-  } else {
-    if (curr->type == Type::unreachable) {
-      if (curr->target->type != Type::unreachable) {
-        bool hasUnreachableOperand = std::any_of(
-          curr->operands.begin(), curr->operands.end(), [](Expression* op) {
-            return op->type == Type::unreachable;
-          });
-        shouldBeTrue(hasUnreachableOperand,
-                     curr,
-                     "call_indirects may only be unreachable if they have "
-                     "unreachable operands");
-      }
-    } else {
-      shouldBeEqual(curr->type,
-                    curr->sig.results,
-                    curr,
-                    "call_indirect type must match callee return type");
-    }
-  }
+  validateCallParamsAndResult(curr, curr->sig);
 }
 
 void FunctionValidator::visitConst(Const* curr) {
@@ -1267,6 +1220,59 @@
   validateAlignment(curr->align, memAlignType, bytes, /*isAtomic=*/false, curr);
 }
 
+void FunctionValidator::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+  shouldBeTrue(
+    getModule()->memory.exists, curr, "Memory operations require a memory");
+  shouldBeTrue(
+    getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
+  if (curr->isLoad()) {
+    shouldBeEqualOrFirstIsUnreachable(
+      curr->type, Type(Type::v128), curr, "loadX_lane must have type v128");
+  } else {
+    shouldBeEqualOrFirstIsUnreachable(
+      curr->type, Type(Type::none), curr, "storeX_lane must have type none");
+  }
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->ptr->type,
+    indexType(),
+    curr,
+    "loadX_lane or storeX_lane address must match memory index type");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->vec->type,
+    Type(Type::v128),
+    curr,
+    "loadX_lane or storeX_lane vector argument must have type v128");
+  size_t lanes;
+  Type memAlignType = Type::none;
+  switch (curr->op) {
+    case LoadLaneVec8x16:
+    case StoreLaneVec8x16:
+      lanes = 16;
+      memAlignType = Type::i32;
+      break;
+    case LoadLaneVec16x8:
+    case StoreLaneVec16x8:
+      lanes = 8;
+      memAlignType = Type::i32;
+      break;
+    case LoadLaneVec32x4:
+    case StoreLaneVec32x4:
+      lanes = 4;
+      memAlignType = Type::i32;
+      break;
+    case LoadLaneVec64x2:
+    case StoreLaneVec64x2:
+      lanes = 2;
+      memAlignType = Type::i64;
+      break;
+    default:
+      WASM_UNREACHABLE("Unexpected SIMDLoadStoreLane op");
+  }
+  Index bytes = curr->getMemBytes();
+  validateAlignment(curr->align, memAlignType, bytes, /*isAtomic=*/false, curr);
+  shouldBeTrue(curr->index < lanes, curr, "invalid lane index");
+}
+
 void FunctionValidator::visitMemoryInit(MemoryInit* curr) {
   shouldBeTrue(getModule()->features.hasBulkMemory(),
                curr,
@@ -1529,6 +1535,7 @@
     case GtUVecI32x4:
     case GeSVecI32x4:
     case GeUVecI32x4:
+    case EqVecI64x2:
     case EqVecF32x4:
     case NeVecF32x4:
     case LtVecF32x4:
@@ -1557,6 +1564,11 @@
     case MaxSVecI8x16:
     case MaxUVecI8x16:
     case AvgrUVecI8x16:
+    case Q15MulrSatSVecI16x8:
+    case ExtMulLowSVecI16x8:
+    case ExtMulHighSVecI16x8:
+    case ExtMulLowUVecI16x8:
+    case ExtMulHighUVecI16x8:
     case AddVecI16x8:
     case AddSatSVecI16x8:
     case AddSatUVecI16x8:
@@ -1577,9 +1589,17 @@
     case MaxSVecI32x4:
     case MaxUVecI32x4:
     case DotSVecI16x8ToVecI32x4:
+    case ExtMulLowSVecI32x4:
+    case ExtMulHighSVecI32x4:
+    case ExtMulLowUVecI32x4:
+    case ExtMulHighUVecI32x4:
     case AddVecI64x2:
     case SubVecI64x2:
     case MulVecI64x2:
+    case ExtMulLowSVecI64x2:
+    case ExtMulHighSVecI64x2:
+    case ExtMulLowUVecI64x2:
+    case ExtMulHighUVecI64x2:
     case AddVecF32x4:
     case SubVecF32x4:
     case MulVecF32x4:
@@ -1824,6 +1844,7 @@
         curr->value->type, Type(Type::f64), curr, "expected f64 splat value");
       break;
     case NotVec128:
+    case PopcntVecI8x16:
     case AbsVecI8x16:
     case AbsVecI16x8:
     case AbsVecI32x4:
@@ -1845,6 +1866,10 @@
     case FloorVecF64x2:
     case TruncVecF64x2:
     case NearestVecF64x2:
+    case ExtAddPairwiseSVecI8x16ToI16x8:
+    case ExtAddPairwiseUVecI8x16ToI16x8:
+    case ExtAddPairwiseSVecI16x8ToI32x4:
+    case ExtAddPairwiseUVecI16x8ToI32x4:
     case TruncSatSVecF32x4ToVecI32x4:
     case TruncSatUVecF32x4ToVecI32x4:
     case TruncSatSVecF64x2ToVecI64x2:
@@ -1861,6 +1886,10 @@
     case WidenHighSVecI16x8ToVecI32x4:
     case WidenLowUVecI16x8ToVecI32x4:
     case WidenHighUVecI16x8ToVecI32x4:
+    case WidenLowSVecI32x4ToVecI64x2:
+    case WidenHighSVecI32x4ToVecI64x2:
+    case WidenLowUVecI32x4ToVecI64x2:
+    case WidenHighUVecI32x4ToVecI64x2:
       shouldBeEqual(curr->type, Type(Type::v128), curr, "expected v128 type");
       shouldBeEqual(
         curr->value->type, Type(Type::v128), curr, "expected v128 operand");
@@ -1868,14 +1897,13 @@
     case AnyTrueVecI8x16:
     case AnyTrueVecI16x8:
     case AnyTrueVecI32x4:
-    case AnyTrueVecI64x2:
     case AllTrueVecI8x16:
     case AllTrueVecI16x8:
     case AllTrueVecI32x4:
-    case AllTrueVecI64x2:
     case BitmaskVecI8x16:
     case BitmaskVecI16x8:
     case BitmaskVecI32x4:
+    case BitmaskVecI64x2:
       shouldBeEqual(curr->type, Type(Type::i32), curr, "expected i32 type");
       shouldBeEqual(
         curr->value->type, Type(Type::v128), curr, "expected v128 operand");
@@ -1944,6 +1972,8 @@
   shouldBeTrue(getModule()->features.hasReferenceTypes(),
                curr,
                "ref.null requires reference-types to be enabled");
+  shouldBeTrue(
+    curr->type.isNullable(), curr, "ref.null types must be nullable");
 }
 
 void FunctionValidator::visitRefIsNull(RefIsNull* curr) {
@@ -1960,8 +1990,15 @@
   shouldBeTrue(getModule()->features.hasReferenceTypes(),
                curr,
                "ref.func requires reference-types to be enabled");
+  if (!info.validateGlobally) {
+    return;
+  }
   auto* func = getModule()->getFunctionOrNull(curr->func);
   shouldBeTrue(!!func, curr, "function argument of ref.func must exist");
+  shouldBeTrue(curr->type.isFunction(),
+               curr,
+               "ref.func must have a function reference type");
+  // TODO: check for non-nullability
 }
 
 void FunctionValidator::visitRefEq(RefEq* curr) {
@@ -2010,13 +2047,13 @@
   shouldBeTrue(getModule()->features.hasExceptionHandling(),
                curr,
                "throw requires exception-handling to be enabled");
-  if (!info.validateGlobally) {
-    return;
-  }
   shouldBeEqual(curr->type,
                 Type(Type::unreachable),
                 curr,
                 "throw's type must be unreachable");
+  if (!info.validateGlobally) {
+    return;
+  }
   auto* event = getModule()->getEventOrNull(curr->event);
   if (!shouldBeTrue(!!event, curr, "throw's event must exist")) {
     return;
@@ -2127,6 +2164,20 @@
   }
 }
 
+void FunctionValidator::visitCallRef(CallRef* curr) {
+  validateReturnCall(curr);
+  shouldBeTrue(getModule()->features.hasTypedFunctionReferences(),
+               curr,
+               "call_ref requires typed-function-references to be enabled");
+  if (curr->target->type != Type::unreachable) {
+    shouldBeTrue(curr->target->type.isFunction(),
+                 curr,
+                 "call_ref target must be a function reference");
+    validateCallParamsAndResult(
+      curr, curr->target->type.getHeapType().getSignature());
+  }
+}
+
 void FunctionValidator::visitI31New(I31New* curr) {
   shouldBeTrue(
     getModule()->features.hasGC(), curr, "i31.new requires gc to be enabled");
@@ -2140,9 +2191,11 @@
   shouldBeTrue(getModule()->features.hasGC(),
                curr,
                "i31.get_s/u requires gc to be enabled");
+  // FIXME: use i31ref here, which is non-nullable, when we support non-
+  // nullability.
   shouldBeSubTypeOrFirstIsUnreachable(
     curr->i31->type,
-    Type::i31ref,
+    Type(HeapType::i31, Nullable),
     curr->i31,
     "i31.get_s/u's argument should be i31ref");
 }
@@ -2150,77 +2203,220 @@
 void FunctionValidator::visitRefTest(RefTest* curr) {
   shouldBeTrue(
     getModule()->features.hasGC(), curr, "ref.test requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): ref.test");
+  if (curr->ref->type != Type::unreachable) {
+    shouldBeTrue(
+      curr->ref->type.isRef(), curr, "ref.test ref must have ref type");
+  }
+  if (curr->rtt->type != Type::unreachable) {
+    shouldBeTrue(
+      curr->rtt->type.isRtt(), curr, "ref.test rtt must have rtt type");
+  }
 }
 
 void FunctionValidator::visitRefCast(RefCast* curr) {
   shouldBeTrue(
     getModule()->features.hasGC(), curr, "ref.cast requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): ref.cast");
+  if (curr->ref->type != Type::unreachable) {
+    shouldBeTrue(
+      curr->ref->type.isRef(), curr, "ref.cast ref must have ref type");
+  }
+  if (curr->rtt->type != Type::unreachable) {
+    shouldBeTrue(
+      curr->rtt->type.isRtt(), curr, "ref.cast rtt must have rtt type");
+  }
 }
 
 void FunctionValidator::visitBrOnCast(BrOnCast* curr) {
   shouldBeTrue(getModule()->features.hasGC(),
                curr,
                "br_on_cast requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): br_on_cast");
+  if (curr->ref->type != Type::unreachable) {
+    shouldBeTrue(
+      curr->ref->type.isRef(), curr, "br_on_cast ref must have ref type");
+  }
+  if (curr->rtt->type != Type::unreachable) {
+    shouldBeTrue(
+      curr->rtt->type.isRtt(), curr, "br_on_cast rtt must have rtt type");
+    shouldBeEqual(curr->rtt->type.getHeapType(),
+                  curr->castType.getHeapType(),
+                  curr,
+                  "br_on_cast rtt must have the proper heap type");
+    noteBreak(curr->name, curr->castType, curr);
+  }
 }
 
 void FunctionValidator::visitRttCanon(RttCanon* curr) {
   shouldBeTrue(
     getModule()->features.hasGC(), curr, "rtt.canon requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): rtt.canon");
+  shouldBeTrue(curr->type.isRtt(), curr, "rtt.canon must have RTT type");
+  auto rtt = curr->type.getRtt();
+  shouldBeEqual(rtt.depth, Index(0), curr, "rtt.canon has a depth of 0");
 }
 
 void FunctionValidator::visitRttSub(RttSub* curr) {
   shouldBeTrue(
     getModule()->features.hasGC(), curr, "rtt.sub requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): rtt.sub");
+  shouldBeTrue(curr->type.isRtt(), curr, "rtt.sub must have RTT type");
+  if (curr->parent->type != Type::unreachable) {
+    shouldBeTrue(
+      curr->parent->type.isRtt(), curr, "rtt.sub parent must have RTT type");
+    auto parentRtt = curr->parent->type.getRtt();
+    auto rtt = curr->type.getRtt();
+    if (rtt.hasDepth() && parentRtt.hasDepth()) {
+      shouldBeEqual(rtt.depth,
+                    parentRtt.depth + 1,
+                    curr,
+                    "rtt.canon has a depth of 1 over the parent");
+    }
+  }
 }
 
 void FunctionValidator::visitStructNew(StructNew* curr) {
   shouldBeTrue(getModule()->features.hasGC(),
                curr,
                "struct.new requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): struct.new");
+  if (curr->type == Type::unreachable) {
+    return;
+  }
+  if (!shouldBeTrue(
+        curr->rtt->type.isRtt(), curr, "struct.new rtt must be rtt")) {
+    return;
+  }
+  auto heapType = curr->rtt->type.getHeapType();
+  if (!shouldBeTrue(
+        heapType.isStruct(), curr, "struct.new heap type must be struct")) {
+    return;
+  }
+  const auto& fields = heapType.getStruct().fields;
+  if (curr->isWithDefault()) {
+    shouldBeTrue(curr->operands.empty(),
+                 curr,
+                 "struct.new_with_default should have no operands");
+    // All the fields must be defaultable.
+    for (const auto& field : fields) {
+      // TODO: add type.isDefaultable()?
+      shouldBeTrue(!field.type.isRef() || field.type.isNullable(),
+                   field,
+                   "struct.new_with_default value type must be defaultable");
+    }
+  } else {
+    // All the fields must have the proper type.
+    for (Index i = 0; i < fields.size(); i++) {
+      shouldBeSubType(curr->operands[i]->type,
+                      fields[i].type,
+                      curr,
+                      "struct.new operand must have proper type");
+    }
+  }
 }
 
 void FunctionValidator::visitStructGet(StructGet* curr) {
   shouldBeTrue(getModule()->features.hasGC(),
                curr,
                "struct.get requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): struct.get");
+  const auto& fields = curr->ref->type.getHeapType().getStruct().fields;
+  shouldBeTrue(curr->index < fields.size(), curr, "bad struct.get field");
+  auto field = fields[curr->index];
+  // If the type is not packed, it must be marked internally as unsigned, by
+  // convention.
+  if (field.type != Type::i32 || field.packedType == Field::not_packed) {
+    shouldBeFalse(curr->signed_, curr, "non-packed get cannot be signed");
+  }
+  if (curr->ref->type == Type::unreachable) {
+    return;
+  }
+  shouldBeEqual(
+    curr->type, field.type, curr, "struct.get must have the proper type");
 }
 
 void FunctionValidator::visitStructSet(StructSet* curr) {
   shouldBeTrue(getModule()->features.hasGC(),
                curr,
                "struct.set requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): struct.set");
+  if (curr->ref->type != Type::unreachable) {
+    const auto& fields = curr->ref->type.getHeapType().getStruct().fields;
+    shouldBeTrue(curr->index < fields.size(), curr, "bad struct.get field");
+    shouldBeEqual(curr->value->type,
+                  fields[curr->index].type,
+                  curr,
+                  "struct.set must have the proper type");
+  }
 }
 
 void FunctionValidator::visitArrayNew(ArrayNew* curr) {
   shouldBeTrue(
     getModule()->features.hasGC(), curr, "array.new requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): array.new");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->size->type, Type(Type::i32), curr, "array.new size must be an i32");
+  if (curr->type == Type::unreachable) {
+    return;
+  }
+  if (!shouldBeTrue(
+        curr->rtt->type.isRtt(), curr, "array.new rtt must be rtt")) {
+    return;
+  }
+  auto heapType = curr->rtt->type.getHeapType();
+  if (!shouldBeTrue(
+        heapType.isArray(), curr, "array.new heap type must be array")) {
+    return;
+  }
+  const auto& element = heapType.getArray().element;
+  if (curr->isWithDefault()) {
+    shouldBeTrue(
+      !curr->init, curr, "array.new_with_default should have no init");
+    // The element must be defaultable.
+    // TODO: add type.isDefaultable()?
+    shouldBeTrue(!element.type.isRef() || element.type.isNullable(),
+                 element,
+                 "array.new_with_default value type must be defaultable");
+  } else {
+    shouldBeTrue(!!curr->init, curr, "array.new should have an init");
+    // The inits must have the proper type.
+    shouldBeSubType(curr->init->type,
+                    element.type,
+                    curr,
+                    "array.new init must have proper type");
+  }
 }
 
 void FunctionValidator::visitArrayGet(ArrayGet* curr) {
   shouldBeTrue(
     getModule()->features.hasGC(), curr, "array.get requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): array.get");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->index->type, Type(Type::i32), curr, "array.get index must be an i32");
+  if (curr->type == Type::unreachable) {
+    return;
+  }
+  const auto& element = curr->ref->type.getHeapType().getArray().element;
+  // If the type is not packed, it must be marked internally as unsigned, by
+  // convention.
+  if (element.type != Type::i32 || element.packedType == Field::not_packed) {
+    shouldBeFalse(curr->signed_, curr, "non-packed get cannot be signed");
+  }
+  shouldBeEqual(
+    curr->type, element.type, curr, "array.get must have the proper type");
 }
 
 void FunctionValidator::visitArraySet(ArraySet* curr) {
   shouldBeTrue(
     getModule()->features.hasGC(), curr, "array.set requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): array.set");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->index->type, Type(Type::i32), curr, "array.set index must be an i32");
+  if (curr->type == Type::unreachable) {
+    return;
+  }
+  const auto& element = curr->ref->type.getHeapType().getArray().element;
+  shouldBeEqual(curr->value->type,
+                element.type,
+                curr,
+                "array.set must have the proper type");
 }
 
 void FunctionValidator::visitArrayLen(ArrayLen* curr) {
   shouldBeTrue(
     getModule()->features.hasGC(), curr, "array.len requires gc to be enabled");
-  WASM_UNREACHABLE("TODO (gc): array.len");
+  shouldBeEqualOrFirstIsUnreachable(
+    curr->type, Type(Type::i32), curr, "array.len result must be an i32");
 }
 
 void FunctionValidator::visitFunction(Function* curr) {
@@ -2241,9 +2437,10 @@
   for (const auto& var : curr->vars) {
     features |= var.getFeatures();
     shouldBeTrue(var.isConcrete(), curr, "vars must be concretely typed");
+    // TODO: check for nullability
   }
   shouldBeTrue(features <= getModule()->features,
-               curr,
+               curr->name,
                "all used types should be allowed");
   if (curr->profile == IRProfile::Poppy) {
     shouldBeTrue(
diff --git a/binaryen/src/wasm/wasm.cpp b/binaryen/src/wasm/wasm.cpp
--- a/binaryen/src/wasm/wasm.cpp
+++ b/binaryen/src/wasm/wasm.cpp
@@ -16,7 +16,6 @@
 
 #include "wasm.h"
 #include "ir/branch-utils.h"
-#include "wasm-printing.h"
 #include "wasm-traversal.h"
 
 namespace wasm {
@@ -47,6 +46,7 @@
 const char* MultivalueFeature = "multivalue";
 const char* GCFeature = "gc";
 const char* Memory64Feature = "memory64";
+const char* TypedFunctionReferencesFeature = "typed-function-references";
 } // namespace UserSections
 } // namespace BinaryConsts
 
@@ -59,6 +59,7 @@
 Name NEW_SIZE("newSize");
 Name MODULE("module");
 Name START("start");
+Name GLOBAL("global");
 Name FUNC("func");
 Name PARAM("param");
 Name RESULT("result");
@@ -71,6 +72,8 @@
 Name ELEM("elem");
 Name LOCAL("local");
 Name TYPE("type");
+Name REF("ref");
+Name NULL_("null");
 Name CALL("call");
 Name CALL_INDIRECT("call_indirect");
 Name BLOCK("block");
@@ -92,16 +95,10 @@
 Name SHARED("shared");
 Name EVENT("event");
 Name ATTR("attr");
-Name ASSIGN_GOT_ENTRIES("__assign_got_enties");
 
 // Expressions
 
-void Expression::dump() {
-  WasmPrinter::printExpression(this,
-                               std::cerr,
-                               /*minify=*/false,
-                               /*full=*/true);
-}
+void Expression::dump() { std::cout << *this << '\n'; }
 
 const char* getExpressionName(Expression* curr) {
   switch (curr->_id) {
@@ -154,15 +151,15 @@
     case Expression::Id::UnreachableId:
       return "unreachable";
     case Expression::Id::AtomicCmpxchgId:
-      return "atomic_cmpxchg";
+      return "atomic.cmpxchg";
     case Expression::Id::AtomicRMWId:
-      return "atomic_rmw";
+      return "atomic.rmw";
     case Expression::Id::AtomicWaitId:
-      return "atomic_wait";
+      return "atomic.wait";
     case Expression::Id::AtomicNotifyId:
-      return "atomic_notify";
+      return "atomic.notify";
     case Expression::Id::AtomicFenceId:
-      return "atomic_fence";
+      return "atomic.fence";
     case Expression::Id::SIMDExtractId:
       return "simd_extract";
     case Expression::Id::SIMDReplaceId:
@@ -175,14 +172,18 @@
       return "simd_shift";
     case Expression::Id::SIMDLoadId:
       return "simd_load";
+    case Expression::Id::SIMDLoadStoreLaneId:
+      return "simd_load_store_lane";
+    case Expression::Id::PrefetchId:
+      return "prefetch";
     case Expression::Id::MemoryInitId:
-      return "memory_init";
+      return "memory.init";
     case Expression::Id::DataDropId:
-      return "data_drop";
+      return "data.drop";
     case Expression::Id::MemoryCopyId:
-      return "memory_copy";
+      return "memory.copy";
     case Expression::Id::MemoryFillId:
-      return "memory_fill";
+      return "memory.fill";
     case Expression::Id::PopId:
       return "pop";
     case Expression::Id::RefNullId:
@@ -209,6 +210,8 @@
       return "i31.new";
     case Expression::Id::I31GetId:
       return "i31.get";
+    case Expression::Id::CallRefId:
+      return "call_ref";
     case Expression::Id::RefTestId:
       return "ref.test";
     case Expression::Id::RefCastId:
@@ -260,72 +263,12 @@
   }
 }
 
-// core AST type checking
-
-struct TypeSeeker : public PostWalker<TypeSeeker> {
-  Expression* target; // look for this one
-  Name targetName;
-  std::vector<Type> types;
-
-  TypeSeeker(Expression* target, Name targetName)
-    : target(target), targetName(targetName) {
-    Expression* temp = target;
-    walk(temp);
-  }
-
-  void visitBreak(Break* curr) {
-    if (curr->name == targetName) {
-      types.push_back(curr->value ? curr->value->type : Type::none);
-    }
-  }
-
-  void visitSwitch(Switch* curr) {
-    for (auto name : curr->targets) {
-      if (name == targetName) {
-        types.push_back(curr->value ? curr->value->type : Type::none);
-      }
-    }
-    if (curr->default_ == targetName) {
-      types.push_back(curr->value ? curr->value->type : Type::none);
-    }
-  }
-
-  void visitBrOnExn(BrOnExn* curr) {
-    if (curr->name == targetName) {
-      types.push_back(curr->sent);
-    }
-  }
-
-  void visitBlock(Block* curr) {
-    if (curr == target) {
-      if (curr->list.size() > 0) {
-        types.push_back(curr->list.back()->type);
-      } else {
-        types.push_back(Type::none);
-      }
-    } else if (curr->name == targetName) {
-      // ignore all breaks til now, they were captured by someone with the same
-      // name
-      types.clear();
-    }
-  }
-
-  void visitLoop(Loop* curr) {
-    if (curr == target) {
-      types.push_back(curr->body->type);
-    } else if (curr->name == targetName) {
-      // ignore all breaks til now, they were captured by someone with the same
-      // name
-      types.clear();
-    }
-  }
-};
-
 // a block is unreachable if one of its elements is unreachable,
 // and there are no branches to it
-static void handleUnreachable(Block* block,
-                              bool breakabilityKnown = false,
-                              bool hasBreak = false) {
+
+static void
+handleUnreachable(Block* block,
+                  Block::Breakability breakability = Block::Unknown) {
   if (block->type == Type::unreachable) {
     return; // nothing to do
   }
@@ -343,10 +286,12 @@
     if (child->type == Type::unreachable) {
       // there is an unreachable child, so we are unreachable, unless we have a
       // break
-      if (!breakabilityKnown) {
-        hasBreak = BranchUtils::BranchSeeker::has(block, block->name);
+      if (breakability == Block::Unknown) {
+        breakability = BranchUtils::BranchSeeker::has(block, block->name)
+                         ? Block::HasBreak
+                         : Block::NoBreak;
       }
-      if (!hasBreak) {
+      if (breakability == Block::NoBreak) {
         block->type = Type::unreachable;
       }
       return;
@@ -355,41 +300,35 @@
 }
 
 void Block::finalize() {
+  if (list.size() == 0) {
+    type = Type::none;
+    return;
+  }
+  // The default type is what is at the end. Next we need to see if breaks and/
+  // or unreachabitily change that.
+  type = list.back()->type;
   if (!name.is()) {
-    if (list.size() > 0) {
-      // nothing branches here, so this is easy
-      // normally the type is the type of the final child
-      type = list.back()->type;
-      // and even if we have an unreachable child somewhere,
-      // we still mark ourselves as having that type,
-      // (block (result i32)
-      //  (return)
-      //  (i32.const 10)
-      // )
-      if (type.isConcrete()) {
-        return;
-      }
-      // if we are unreachable, we are done
-      if (type == Type::unreachable) {
-        return;
-      }
-      // we may still be unreachable if we have an unreachable
-      // child
-      for (auto* child : list) {
-        if (child->type == Type::unreachable) {
-          type = Type::unreachable;
-          return;
-        }
-      }
+    // Nothing branches here, so this is easy.
+    handleUnreachable(this, NoBreak);
+    return;
+  }
+
+  // The default type is according to the value that flows out.
+  BranchUtils::BranchSeeker seeker(this->name);
+  Expression* temp = this;
+  seeker.walk(temp);
+  if (seeker.found) {
+    // Take the branch values into account.
+    if (seeker.valueType != Type::none) {
+      type = Type::getLeastUpperBound(type, seeker.valueType);
     } else {
+      // No value is sent, but as we have a branch we are not unreachable.
       type = Type::none;
     }
-    return;
+  } else {
+    // There are no branches, so this block may be unreachable.
+    handleUnreachable(this, NoBreak);
   }
-
-  TypeSeeker seeker(this, this->name);
-  type = Type::mergeTypes(seeker.types);
-  handleUnreachable(this);
 }
 
 void Block::finalize(Type type_) {
@@ -399,10 +338,10 @@
   }
 }
 
-void Block::finalize(Type type_, bool hasBreak) {
+void Block::finalize(Type type_, Breakability breakability) {
   type = type_;
   if (type == Type::none && list.size() > 0) {
-    handleUnreachable(this, true, hasBreak);
+    handleUnreachable(this, breakability);
   }
 }
 
@@ -456,13 +395,16 @@
 
 void Switch::finalize() { type = Type::unreachable; }
 
-template<typename T> void handleUnreachableOperands(T* curr) {
+// Sets the type to unreachable if there is an unreachable operand. Returns true
+// if so.
+template<typename T> bool handleUnreachableOperands(T* curr) {
   for (auto* child : curr->operands) {
     if (child->type == Type::unreachable) {
       curr->type = Type::unreachable;
-      break;
+      return true;
     }
   }
+  return false;
 }
 
 void Call::finalize() {
@@ -674,6 +616,52 @@
   WASM_UNREACHABLE("unexpected op");
 }
 
+void SIMDLoadStoreLane::finalize() {
+  assert(ptr && vec);
+  type = isLoad() ? Type::v128 : Type::none;
+  if (ptr->type == Type::unreachable || vec->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
+
+Index SIMDLoadStoreLane::getMemBytes() {
+  switch (op) {
+    case LoadLaneVec8x16:
+    case StoreLaneVec8x16:
+      return 1;
+    case LoadLaneVec16x8:
+    case StoreLaneVec16x8:
+      return 2;
+    case LoadLaneVec32x4:
+    case StoreLaneVec32x4:
+      return 4;
+    case LoadLaneVec64x2:
+    case StoreLaneVec64x2:
+      return 8;
+  }
+  WASM_UNREACHABLE("unexpected op");
+}
+
+bool SIMDLoadStoreLane::isStore() {
+  switch (op) {
+    case StoreLaneVec8x16:
+    case StoreLaneVec16x8:
+    case StoreLaneVec32x4:
+    case StoreLaneVec64x2:
+      return true;
+    case LoadLaneVec16x8:
+    case LoadLaneVec32x4:
+    case LoadLaneVec64x2:
+    case LoadLaneVec8x16:
+      return false;
+  }
+  WASM_UNREACHABLE("unexpected op");
+}
+
+void Prefetch::finalize() {
+  type = ptr->type == Type::unreachable ? Type::unreachable : Type::none;
+}
+
 Const* Const::set(Literal value_) {
   value = value_;
   type = value.type;
@@ -782,6 +770,7 @@
     case AbsVecI8x16:
     case AbsVecI16x8:
     case AbsVecI32x4:
+    case PopcntVecI8x16:
     case NegVecI8x16:
     case NegVecI16x8:
     case NegVecI32x4:
@@ -800,6 +789,10 @@
     case FloorVecF64x2:
     case TruncVecF64x2:
     case NearestVecF64x2:
+    case ExtAddPairwiseSVecI8x16ToI16x8:
+    case ExtAddPairwiseUVecI8x16ToI16x8:
+    case ExtAddPairwiseSVecI16x8ToI32x4:
+    case ExtAddPairwiseUVecI16x8ToI32x4:
     case TruncSatSVecF32x4ToVecI32x4:
     case TruncSatUVecF32x4ToVecI32x4:
     case TruncSatSVecF64x2ToVecI64x2:
@@ -816,19 +809,22 @@
     case WidenHighSVecI16x8ToVecI32x4:
     case WidenLowUVecI16x8ToVecI32x4:
     case WidenHighUVecI16x8ToVecI32x4:
+    case WidenLowSVecI32x4ToVecI64x2:
+    case WidenHighSVecI32x4ToVecI64x2:
+    case WidenLowUVecI32x4ToVecI64x2:
+    case WidenHighUVecI32x4ToVecI64x2:
       type = Type::v128;
       break;
     case AnyTrueVecI8x16:
     case AnyTrueVecI16x8:
     case AnyTrueVecI32x4:
-    case AnyTrueVecI64x2:
     case AllTrueVecI8x16:
     case AllTrueVecI16x8:
     case AllTrueVecI32x4:
-    case AllTrueVecI64x2:
     case BitmaskVecI8x16:
     case BitmaskVecI16x8:
     case BitmaskVecI32x4:
+    case BitmaskVecI64x2:
       type = Type::i32;
       break;
 
@@ -920,15 +916,13 @@
   }
 }
 
-void RefNull::finalize(HeapType heapType) { type = Type(heapType, true); }
+void RefNull::finalize(HeapType heapType) { type = Type(heapType, Nullable); }
 
 void RefNull::finalize(Type type_) {
-  assert(type_ == Type::unreachable || type_.isNullable());
   type = type_;
 }
 
 void RefNull::finalize() {
-  assert(type == Type::unreachable || type.isNullable());
 }
 
 void RefIsNull::finalize() {
@@ -939,8 +933,13 @@
   type = Type::i32;
 }
 
-void RefFunc::finalize() { type = Type::funcref; }
+void RefFunc::finalize() {
+  // No-op. We assume that the full proper typed function type has been applied
+  // previously.
+}
 
+void RefFunc::finalize(Type type_) { type = type_; }
+
 void RefEq::finalize() {
   if (left->type == Type::unreachable || right->type == Type::unreachable) {
     type = Type::unreachable;
@@ -1009,19 +1008,138 @@
   }
 }
 
-// TODO (gc): ref.test
-// TODO (gc): ref.cast
-// TODO (gc): br_on_cast
-// TODO (gc): rtt.canon
-// TODO (gc): rtt.sub
-// TODO (gc): struct.new
-// TODO (gc): struct.get
-// TODO (gc): struct.set
-// TODO (gc): array.new
-// TODO (gc): array.get
-// TODO (gc): array.set
-// TODO (gc): array.len
+void CallRef::finalize() {
+  handleUnreachableOperands(this);
+  if (isReturn) {
+    type = Type::unreachable;
+  }
+  if (target->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+}
 
+void CallRef::finalize(Type type_) {
+  type = type_;
+  finalize();
+}
+
+void RefTest::finalize() {
+  if (ref->type == Type::unreachable || rtt->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::i32;
+  }
+}
+
+// Helper to get the cast type for a cast instruction. They all look at the rtt
+// operand's type.
+template<typename T> static Type doGetCastType(T* curr) {
+  if (curr->rtt->type == Type::unreachable) {
+    // We don't have the RTT type, so just return unreachable. The type in this
+    // case should not matter in practice, but it may be seen while debugging.
+    return Type::unreachable;
+  }
+  // TODO: make non-nullable when we support that
+  return Type(curr->rtt->type.getHeapType(), Nullable);
+}
+
+Type RefTest::getCastType() { return doGetCastType(this); }
+
+void RefCast::finalize() {
+  if (ref->type == Type::unreachable || rtt->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = getCastType();
+  }
+}
+
+Type RefCast::getCastType() { return doGetCastType(this); }
+
+void BrOnCast::finalize() {
+  if (ref->type == Type::unreachable || rtt->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = ref->type;
+  }
+}
+
+Type BrOnCast::getCastType() { return castType; }
+
+void RttCanon::finalize() {
+  // Nothing to do - the type must have been set already during construction.
+}
+
+void RttSub::finalize() {
+  if (parent->type == Type::unreachable) {
+    type = Type::unreachable;
+  }
+  // Else nothing to do - the type must have been set already during
+  // construction.
+}
+
+void StructNew::finalize() {
+  if (rtt->type == Type::unreachable) {
+    type = Type::unreachable;
+    return;
+  }
+  if (handleUnreachableOperands(this)) {
+    return;
+  }
+  // TODO: make non-nullable when we support that
+  type = Type(rtt->type.getHeapType(), Nullable);
+}
+
+void StructGet::finalize() {
+  if (ref->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = ref->type.getHeapType().getStruct().fields[index].type;
+  }
+}
+
+void StructSet::finalize() {
+  if (ref->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::none;
+  }
+}
+
+void ArrayNew::finalize() {
+  if (rtt->type == Type::unreachable || size->type == Type::unreachable ||
+      (init && init->type == Type::unreachable)) {
+    type = Type::unreachable;
+    return;
+  }
+  // TODO: make non-nullable when we support that
+  type = Type(rtt->type.getHeapType(), Nullable);
+}
+
+void ArrayGet::finalize() {
+  if (ref->type == Type::unreachable || index->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = ref->type.getHeapType().getArray().element.type;
+  }
+}
+
+void ArraySet::finalize() {
+  if (ref->type == Type::unreachable || index->type == Type::unreachable ||
+      value->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::none;
+  }
+}
+
+void ArrayLen::finalize() {
+  if (ref->type == Type::unreachable) {
+    type = Type::unreachable;
+  } else {
+    type = Type::i32;
+  }
+}
+
 size_t Function::getNumParams() { return sig.params.size(); }
 
 size_t Function::getNumVars() { return vars.size(); }
@@ -1197,20 +1315,20 @@
   return addModuleElement(events, eventsMap, curr, "addEvent");
 }
 
-Export* Module::addExport(std::unique_ptr<Export> curr) {
+Export* Module::addExport(std::unique_ptr<Export>&& curr) {
   return addModuleElement(exports, exportsMap, std::move(curr), "addExport");
 }
 
-Function* Module::addFunction(std::unique_ptr<Function> curr) {
+Function* Module::addFunction(std::unique_ptr<Function>&& curr) {
   return addModuleElement(
     functions, functionsMap, std::move(curr), "addFunction");
 }
 
-Global* Module::addGlobal(std::unique_ptr<Global> curr) {
+Global* Module::addGlobal(std::unique_ptr<Global>&& curr) {
   return addModuleElement(globals, globalsMap, std::move(curr), "addGlobal");
 }
 
-Event* Module::addEvent(std::unique_ptr<Event> curr) {
+Event* Module::addEvent(std::unique_ptr<Event>&& curr) {
   return addModuleElement(events, eventsMap, std::move(curr), "addEvent");
 }
 
diff --git a/binaryen/src/wasm2js.h b/binaryen/src/wasm2js.h
--- a/binaryen/src/wasm2js.h
+++ b/binaryen/src/wasm2js.h
@@ -92,6 +92,37 @@
   return false;
 }
 
+bool hasActiveSegments(Module& wasm) {
+  for (Index i = 0; i < wasm.memory.segments.size(); i++) {
+    if (!wasm.memory.segments[i].isPassive) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool needsBufferView(Module& wasm) {
+  if (!wasm.memory.exists) {
+    return false;
+  }
+
+  // If there are any active segments, initActiveSegments needs access
+  // to bufferView.
+  if (hasActiveSegments(wasm)) {
+    return true;
+  }
+
+  // The special support functions are emitted as part of the JS glue, if we
+  // need them.
+  bool need = false;
+  ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
+    if (ABI::wasm2js::isHelper(import->base)) {
+      need = true;
+    }
+  });
+  return need;
+}
+
 IString stringToIString(std::string str) { return IString(str.c_str(), false); }
 
 // Used when taking a wasm name and generating a JS identifier. Each scope here
@@ -373,7 +404,7 @@
 
 #ifndef NDEBUG
   if (!WasmValidator().validate(*wasm)) {
-    WasmPrinter::printModule(wasm);
+    std::cout << *wasm << '\n';
     Fatal() << "error in validating wasm2js output";
   }
 #endif
@@ -381,9 +412,9 @@
   Ref ret = ValueBuilder::makeToplevel();
   Ref asmFunc = ValueBuilder::makeFunction(funcName);
   ret[1]->push_back(asmFunc);
-  ValueBuilder::appendArgumentToFunction(asmFunc, GLOBAL);
   ValueBuilder::appendArgumentToFunction(asmFunc, ENV);
 
+  // add memory import
   if (wasm->memory.exists) {
     if (wasm->memory.imported()) {
       // find memory and buffer in imports
@@ -415,8 +446,15 @@
             ValueBuilder::makeName(WASM_MEMORY_GROW))));
       }
     } else {
-      // find memory as third argument
-      ValueBuilder::appendArgumentToFunction(asmFunc, BUFFER);
+      Ref theVar = ValueBuilder::makeVar();
+      asmFunc[3]->push_back(theVar);
+      ValueBuilder::appendToVar(
+        theVar,
+        BUFFER,
+        ValueBuilder::makeNew(ValueBuilder::makeCall(
+          ValueBuilder::makeName("ArrayBuffer"),
+          ValueBuilder::makeInt(Address::address32_t(wasm->memory.initial.addr *
+                                                     Memory::kPageSize)))));
     }
   }
 
@@ -429,6 +467,7 @@
       FUNCTION_TABLE,
       ValueBuilder::makeDot(ValueBuilder::makeName(ENV), wasm->table.base));
   }
+
   // create heaps, etc
   addBasics(asmFunc[3], wasm);
   ModuleUtils::iterImportedFunctions(
@@ -479,6 +518,18 @@
     asmFunc[3]->push_back(ValueBuilder::makeName("// EMSCRIPTEN_END_FUNCS\n"));
   }
 
+  if (needsBufferView(*wasm)) {
+    asmFunc[3]->push_back(
+      ValueBuilder::makeBinary(ValueBuilder::makeName("bufferView"),
+                               SET,
+                               ValueBuilder::makeName(HEAPU8)));
+  }
+  if (hasActiveSegments(*wasm)) {
+    asmFunc[3]->push_back(
+      ValueBuilder::makeCall(ValueBuilder::makeName("initActiveSegments"),
+                             ValueBuilder::makeName(ENV)));
+  }
+
   addTable(asmFunc[3], wasm);
   addStart(asmFunc[3], wasm);
   addExports(asmFunc[3], wasm);
@@ -491,12 +542,10 @@
     auto addHeap = [&](IString name, IString view) {
       Ref theVar = ValueBuilder::makeVar();
       ast->push_back(theVar);
-      ValueBuilder::appendToVar(
-        theVar,
-        name,
-        ValueBuilder::makeNew(ValueBuilder::makeCall(
-          ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), view),
-          ValueBuilder::makeName(BUFFER))));
+      ValueBuilder::appendToVar(theVar,
+                                name,
+                                ValueBuilder::makeNew(ValueBuilder::makeCall(
+                                  view, ValueBuilder::makeName(BUFFER))));
     };
     addHeap(HEAP8, INT8ARRAY);
     addHeap(HEAP16, INT16ARRAY);
@@ -512,10 +561,7 @@
     Ref theVar = ValueBuilder::makeVar();
     ast->push_back(theVar);
     ValueBuilder::appendToVar(
-      theVar,
-      name,
-      ValueBuilder::makeDot(
-        ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), MATH), base));
+      theVar, name, ValueBuilder::makeDot(ValueBuilder::makeName(MATH), base));
   };
   addMath(MATH_IMUL, IMUL);
   addMath(MATH_FROUND, FROUND);
@@ -525,6 +571,7 @@
   addMath(MATH_MAX, MAX);
   addMath(MATH_FLOOR, FLOOR);
   addMath(MATH_CEIL, CEIL);
+  addMath(MATH_TRUNC, TRUNC);
   addMath(MATH_SQRT, SQRT);
   // abort function
   Ref abortVar = ValueBuilder::makeVar();
@@ -537,16 +584,11 @@
   // NaN and Infinity variables
   Ref nanVar = ValueBuilder::makeVar();
   ast->push_back(nanVar);
-  ValueBuilder::appendToVar(
-    nanVar,
-    "nan",
-    ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), "NaN"));
+  ValueBuilder::appendToVar(nanVar, "nan", ValueBuilder::makeName("NaN"));
   Ref infinityVar = ValueBuilder::makeVar();
   ast->push_back(infinityVar);
   ValueBuilder::appendToVar(
-    infinityVar,
-    "infinity",
-    ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), "Infinity"));
+    infinityVar, "infinity", ValueBuilder::makeName("Infinity"));
 }
 
 void Wasm2JSBuilder::addFunctionImport(Ref ast, Function* import) {
@@ -1624,6 +1666,11 @@
               ret = ValueBuilder::makeCall(
                 MATH_FLOOR, visit(curr->value, EXPRESSION_RESULT));
               break;
+            case TruncFloat32:
+            case TruncFloat64:
+              ret = ValueBuilder::makeCall(
+                MATH_TRUNC, visit(curr->value, EXPRESSION_RESULT));
+              break;
             case SqrtFloat32:
             case SqrtFloat64:
               ret = ValueBuilder::makeCall(
@@ -1677,8 +1724,6 @@
             // TODO: more complex unary conversions
             case NearestFloat32:
             case NearestFloat64:
-            case TruncFloat32:
-            case TruncFloat64:
               WASM_UNREACHABLE(
                 "operation should have been removed in previous passes");
 
@@ -1939,6 +1984,7 @@
     }
 
     Ref visitNop(Nop* curr) { return ValueBuilder::makeToplevel(); }
+    Ref visitPrefetch(Prefetch* curr) { return ValueBuilder::makeToplevel(); }
 
     Ref visitUnreachable(Unreachable* curr) {
       return ValueBuilder::makeCall(ABORT_FUNC);
@@ -1979,22 +2025,22 @@
         getHeapAndAdjustedPointer(curr->bytes, curr->ptr, curr->offset);
       IString target;
       switch (curr->op) {
-        case AtomicRMWOp::Add:
+        case RMWAdd:
           target = IString("add");
           break;
-        case AtomicRMWOp::Sub:
+        case RMWSub:
           target = IString("sub");
           break;
-        case AtomicRMWOp::And:
+        case RMWAnd:
           target = IString("and");
           break;
-        case AtomicRMWOp::Or:
+        case RMWOr:
           target = IString("or");
           break;
-        case AtomicRMWOp::Xor:
+        case RMWXor:
           target = IString("xor");
           break;
-        case AtomicRMWOp::Xchg:
+        case RMWXchg:
           target = IString("exchange");
           break;
         default:
@@ -2070,6 +2116,10 @@
       unimplemented(curr);
       WASM_UNREACHABLE("unimp");
     }
+    Ref visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
     Ref visitMemoryInit(MemoryInit* curr) {
       ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::MEMORY_INIT);
       return ValueBuilder::makeCall(ABI::wasm2js::MEMORY_INIT,
@@ -2149,6 +2199,10 @@
       unimplemented(curr);
       WASM_UNREACHABLE("unimp");
     }
+    Ref visitCallRef(CallRef* curr) {
+      unimplemented(curr);
+      WASM_UNREACHABLE("unimp");
+    }
     Ref visitRefTest(RefTest* curr) {
       unimplemented(curr);
       WASM_UNREACHABLE("unimp");
@@ -2289,12 +2343,11 @@
 
   Ref newHEAP8 = ValueBuilder::makeVar();
   ValueBuilder::appendToBlock(block, newHEAP8);
-  ValueBuilder::appendToVar(
-    newHEAP8,
-    IString("newHEAP8"),
-    ValueBuilder::makeNew(ValueBuilder::makeCall(
-      ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), INT8ARRAY),
-      ValueBuilder::makeName(IString("newBuffer")))));
+  ValueBuilder::appendToVar(newHEAP8,
+                            IString("newHEAP8"),
+                            ValueBuilder::makeNew(ValueBuilder::makeCall(
+                              ValueBuilder::makeName(INT8ARRAY),
+                              ValueBuilder::makeName(IString("newBuffer")))));
 
   ValueBuilder::appendToBlock(
     block,
@@ -2303,12 +2356,6 @@
                             IString("set")),
       ValueBuilder::makeName(HEAP8)));
 
-  ValueBuilder::appendToBlock(
-    block,
-    ValueBuilder::makeBinary(ValueBuilder::makeName(HEAP8),
-                             SET,
-                             ValueBuilder::makeName(IString("newHEAP8"))));
-
   auto setHeap = [&](IString name, IString view) {
     ValueBuilder::appendToBlock(
       block,
@@ -2316,7 +2363,7 @@
         ValueBuilder::makeName(name),
         SET,
         ValueBuilder::makeNew(ValueBuilder::makeCall(
-          ValueBuilder::makeDot(ValueBuilder::makeName(GLOBAL), view),
+          ValueBuilder::makeName(view),
           ValueBuilder::makeName(IString("newBuffer"))))));
   };
 
@@ -2343,9 +2390,17 @@
         ValueBuilder::makeDot(ValueBuilder::makeName("memory"),
                               ValueBuilder::makeName(BUFFER)),
         SET,
-        ValueBuilder::makeName(IString("newBuffer"))));
+        ValueBuilder::makeName(BUFFER)));
   }
 
+  if (needsBufferView(*wasm)) {
+    ValueBuilder::appendToBlock(
+      block,
+      ValueBuilder::makeBinary(ValueBuilder::makeName("bufferView"),
+                               SET,
+                               ValueBuilder::makeName(HEAPU8)));
+  }
+
   memoryGrowFunc[3]->push_back(
     ValueBuilder::makeReturn(ValueBuilder::makeName(IString("oldPages"))));
 
@@ -2377,9 +2432,7 @@
   void emitPostEmscripten();
   void emitPostES6();
 
-  void emitMemory(std::string buffer,
-                  std::string segmentWriter,
-                  std::function<std::string(std::string)> accessGlobal);
+  void emitMemory();
   void emitSpecialSupport();
 };
 
@@ -2411,11 +2464,12 @@
         << "}\n\n";
   }
 
+  emitMemory();
   emitSpecialSupport();
 }
 
 void Wasm2JSGlue::emitPreEmscripten() {
-  out << "function instantiate(asmLibraryArg, wasmMemory) {\n";
+  out << "function instantiate(asmLibraryArg) {\n";
 }
 
 void Wasm2JSGlue::emitPreES6() {
@@ -2462,29 +2516,7 @@
 }
 
 void Wasm2JSGlue::emitPostEmscripten() {
-  emitMemory("wasmMemory.buffer", "writeSegment", [](std::string globalName) {
-    return std::string("asmLibraryArg['") + asmangle(globalName) + "']";
-  });
-
-  out << "return asmFunc({\n"
-      << "    'Int8Array': Int8Array,\n"
-      << "    'Int16Array': Int16Array,\n"
-      << "    'Int32Array': Int32Array,\n"
-      << "    'Uint8Array': Uint8Array,\n"
-      << "    'Uint16Array': Uint16Array,\n"
-      << "    'Uint32Array': Uint32Array,\n"
-      << "    'Float32Array': Float32Array,\n"
-      << "    'Float64Array': Float64Array,\n"
-      << "    'NaN': NaN,\n"
-      << "    'Infinity': Infinity,\n"
-      << "    'Math': Math\n"
-      << "  },\n"
-      << "  asmLibraryArg,\n"
-      << "  wasmMemory.buffer\n"
-      << ")"
-      << "\n"
-      << "\n"
-      << "}";
+  out << "  return asmFunc(asmLibraryArg);\n}\n";
 }
 
 void Wasm2JSGlue::emitPostES6() {
@@ -2494,32 +2526,15 @@
   //
   // Note that the translation here expects that the lower values of this memory
   // can be used for conversions, so make sure there's at least one page.
-  if (wasm.memory.exists) {
+  if (wasm.memory.exists && wasm.memory.imported()) {
     out << "var mem" << moduleName.str << " = new ArrayBuffer("
         << wasm.memory.initial.addr * Memory::kPageSize << ");\n";
-
-    emitMemory(std::string("mem") + moduleName.str,
-               std::string("assign") + moduleName.str,
-               [](std::string globalName) { return globalName; });
   }
 
   // Actually invoke the `asmFunc` generated function, passing in all global
   // values followed by all imports
-  out << "var ret" << moduleName.str << " = " << moduleName.str << "({\n"
-      << "    Math,\n"
-      << "    Int8Array,\n"
-      << "    Uint8Array,\n"
-      << "    Int16Array,\n"
-      << "    Uint16Array,\n"
-      << "    Int32Array,\n"
-      << "    Uint32Array,\n"
-      << "    Float32Array,\n"
-      << "    Float64Array,\n"
-      << "    NaN,\n"
-      << "    Infinity\n"
-      << "  }, {\n";
-
-  out << "    abort: function() { throw new Error('abort'); }";
+  out << "var ret" << moduleName.str << " = " << moduleName.str << "(";
+  out << "  { abort: function() { throw new Error('abort'); }";
 
   ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
     // The special helpers are emitted in the glue, see code and comments
@@ -2549,11 +2564,7 @@
     out << ",\n    " << asmangle(import->base.str);
   });
 
-  if (wasm.memory.exists && !wasm.memory.imported()) {
-    out << "\n  },\n  mem" << moduleName.str << "\n);\n";
-  } else {
-    out << "\n  });\n";
-  }
+  out << "\n  });\n";
 
   if (flags.allowAsserts) {
     return;
@@ -2584,28 +2595,35 @@
   }
 }
 
-void Wasm2JSGlue::emitMemory(
-  std::string buffer,
-  std::string segmentWriter,
-  std::function<std::string(std::string)> accessGlobal) {
-  if (!wasm.memory.exists) {
-    return;
-  }
-  // Create a helper bufferView to access the buffer if we need one. We use it
-  // for creating memory segments if we have any (we may not if the segments are
-  // shipped in a side .mem file, for example), and also in bulk memory
-  // operations.
-  if (!wasm.memory.segments.empty() || wasm.features.hasBulkMemory()) {
-    out << "var bufferView = new Uint8Array(" << buffer << ");\n";
+void Wasm2JSGlue::emitMemory() {
+  if (needsBufferView(wasm)) {
+    // Create a helper bufferView to access the buffer if we need one. We use it
+    // for creating memory segments if we have any (we may not if the segments
+    // are shipped in a side .mem file, for example), and also in bulk memory
+    // operations.
+    // This will get assigned during `asmFunc` (and potentially re-assigned
+    // during __wasm_memory_grow).
+    // TODO: We should probably just share a single HEAPU8 var.
+    out << "  var bufferView;\n";
   }
+
   // If there are no memory segments, we don't need to emit any support code for
   // segment creation.
-  if (wasm.memory.segments.empty()) {
+  if ((!wasm.memory.exists) || wasm.memory.segments.empty()) {
     return;
   }
 
+  // If we have passive memory segments, we need to store those.
+  for (auto& seg : wasm.memory.segments) {
+    if (seg.isPassive) {
+      out << "  var memorySegments = {};\n";
+      break;
+    }
+  }
+
   out <<
-    R"(for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
+    R"(  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
     base64ReverseLookup[48+i] = 52+i; // '0-9'
     base64ReverseLookup[65+i] = i; // 'A-Z'
     base64ReverseLookup[97+i] = 26+i; // 'a-z'
@@ -2628,29 +2646,13 @@
     out << R"(
     return uint8Array;)";
   }
-  out << R"( 
+  out << R"(
   }
-  )";
-
-  auto globalOffset = [&](const Memory::Segment& segment) {
-    if (auto* c = segment.offset->dynCast<Const>()) {
-      return std::to_string(c->value.getInteger());
-    }
-    if (auto* get = segment.offset->dynCast<GlobalGet>()) {
-      auto internalName = get->name;
-      auto importedName = wasm.getGlobal(internalName)->base;
-      return accessGlobal(asmangle(importedName.str));
-    }
-    Fatal() << "non-constant offsets aren't supported yet\n";
-  };
+)";
 
   for (Index i = 0; i < wasm.memory.segments.size(); i++) {
     auto& seg = wasm.memory.segments[i];
-    if (!seg.isPassive) {
-      // Plain active segments are decoded directly into the main memory.
-      out << "base64DecodeToExistingUint8Array(bufferView, "
-          << globalOffset(seg) << ", \"" << base64Encode(seg.data) << "\");\n";
-    } else {
+    if (seg.isPassive) {
       // Fancy passive segments are decoded into typed arrays on the side, for
       // later copying.
       out << "memorySegments[" << i
@@ -2659,6 +2661,32 @@
           << ", 0, \"" << base64Encode(seg.data) << "\");\n";
     }
   }
+
+  if (hasActiveSegments(wasm)) {
+    auto globalOffset = [&](const Memory::Segment& segment) {
+      if (auto* c = segment.offset->dynCast<Const>()) {
+        return std::to_string(c->value.getInteger());
+      }
+      if (auto* get = segment.offset->dynCast<GlobalGet>()) {
+        auto internalName = get->name;
+        auto importedName = wasm.getGlobal(internalName)->base;
+        return std::string("imports[") + asmangle(importedName.str) + "]";
+      }
+      Fatal() << "non-constant offsets aren't supported yet\n";
+    };
+
+    out << "function initActiveSegments(imports) {\n";
+    for (Index i = 0; i < wasm.memory.segments.size(); i++) {
+      auto& seg = wasm.memory.segments[i];
+      if (!seg.isPassive) {
+        // Plain active segments are decoded directly into the main memory.
+        out << "  base64DecodeToExistingUint8Array(bufferView, "
+            << globalOffset(seg) << ", \"" << base64Encode(seg.data)
+            << "\");\n";
+      }
+    }
+    out << "}\n";
+  }
 }
 
 void Wasm2JSGlue::emitSpecialSupport() {
@@ -2733,15 +2761,6 @@
   var f64ScratchView = new Float64Array(scratchBuffer);
   )";
 
-  // If we have passive memory segments, or bulk memory operations that operate
-  // on segment indexes, we need to store those.
-  bool needMemorySegmentsList = false;
-  for (auto& seg : wasm.memory.segments) {
-    if (seg.isPassive) {
-      needMemorySegmentsList = true;
-    }
-  }
-
   ModuleUtils::iterImportedFunctions(wasm, [&](Function* import) {
     if (import->base == ABI::wasm2js::SCRATCH_STORE_I32) {
       out << R"(
@@ -2780,7 +2799,6 @@
   }
       )";
     } else if (import->base == ABI::wasm2js::MEMORY_INIT) {
-      needMemorySegmentsList = true;
       out << R"(
   function wasm2js_memory_init(segment, dest, offset, size) {
     // TODO: traps on invalid things
@@ -2804,7 +2822,6 @@
   }
       )";
     } else if (import->base == ABI::wasm2js::DATA_DROP) {
-      needMemorySegmentsList = true;
       out << R"(
   function wasm2js_data_drop(segment) {
     // TODO: traps on invalid things
@@ -2874,12 +2891,6 @@
       )";
     }
   });
-
-  if (needMemorySegmentsList) {
-    out << R"(
-  var memorySegments = {};
-    )";
-  }
 
   out << '\n';
 }
diff --git a/binaryen/test/atomics.wast b/binaryen/test/atomics.wast
--- a/binaryen/test/atomics.wast
+++ b/binaryen/test/atomics.wast
@@ -138,40 +138,40 @@
   (local $0 i32)
   (local $1 i64)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $0)
     (local.get $0)
     (local.get $1)
    )
   )
   (drop
-   (i32.atomic.wait offset=4 align=4
+   (memory.atomic.wait32 offset=4 align=4
     (local.get $0)
     (local.get $0)
     (local.get $1)
    )
   )
   (drop
-   (atomic.notify
+   (memory.atomic.notify
     (local.get $0)
     (local.get $0)
    )
   )
   (drop
-   (atomic.notify offset=24 align=4
+   (memory.atomic.notify offset=24 align=4
     (local.get $0)
     (local.get $0)
    )
   )
   (drop
-   (i64.atomic.wait
+   (memory.atomic.wait64
     (local.get $0)
     (local.get $1)
     (local.get $1)
    )
   )
   (drop
-   (i64.atomic.wait align=8 offset=16
+   (memory.atomic.wait64 align=8 offset=16
     (local.get $0)
     (local.get $1)
     (local.get $1)
diff --git a/binaryen/test/atomics.wast.from-wast b/binaryen/test/atomics.wast.from-wast
--- a/binaryen/test/atomics.wast.from-wast
+++ b/binaryen/test/atomics.wast.from-wast
@@ -138,40 +138,40 @@
   (local $0 i32)
   (local $1 i64)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $0)
     (local.get $0)
     (local.get $1)
    )
   )
   (drop
-   (i32.atomic.wait offset=4
+   (memory.atomic.wait32 offset=4
     (local.get $0)
     (local.get $0)
     (local.get $1)
    )
   )
   (drop
-   (atomic.notify
+   (memory.atomic.notify
     (local.get $0)
     (local.get $0)
    )
   )
   (drop
-   (atomic.notify offset=24
+   (memory.atomic.notify offset=24
     (local.get $0)
     (local.get $0)
    )
   )
   (drop
-   (i64.atomic.wait
+   (memory.atomic.wait64
     (local.get $0)
     (local.get $1)
     (local.get $1)
    )
   )
   (drop
-   (i64.atomic.wait offset=16
+   (memory.atomic.wait64 offset=16
     (local.get $0)
     (local.get $1)
     (local.get $1)
diff --git a/binaryen/test/atomics.wast.fromBinary b/binaryen/test/atomics.wast.fromBinary
--- a/binaryen/test/atomics.wast.fromBinary
+++ b/binaryen/test/atomics.wast.fromBinary
@@ -138,40 +138,40 @@
   (local $0 i32)
   (local $1 i64)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $0)
     (local.get $0)
     (local.get $1)
    )
   )
   (drop
-   (i32.atomic.wait offset=4
+   (memory.atomic.wait32 offset=4
     (local.get $0)
     (local.get $0)
     (local.get $1)
    )
   )
   (drop
-   (atomic.notify
+   (memory.atomic.notify
     (local.get $0)
     (local.get $0)
    )
   )
   (drop
-   (atomic.notify offset=24
+   (memory.atomic.notify offset=24
     (local.get $0)
     (local.get $0)
    )
   )
   (drop
-   (i64.atomic.wait
+   (memory.atomic.wait64
     (local.get $0)
     (local.get $1)
     (local.get $1)
    )
   )
   (drop
-   (i64.atomic.wait offset=16
+   (memory.atomic.wait64 offset=16
     (local.get $0)
     (local.get $1)
     (local.get $1)
diff --git a/binaryen/test/atomics.wast.fromBinary.noDebugInfo b/binaryen/test/atomics.wast.fromBinary.noDebugInfo
--- a/binaryen/test/atomics.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/atomics.wast.fromBinary.noDebugInfo
@@ -138,40 +138,40 @@
   (local $0 i32)
   (local $1 i64)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $0)
     (local.get $0)
     (local.get $1)
    )
   )
   (drop
-   (i32.atomic.wait offset=4
+   (memory.atomic.wait32 offset=4
     (local.get $0)
     (local.get $0)
     (local.get $1)
    )
   )
   (drop
-   (atomic.notify
+   (memory.atomic.notify
     (local.get $0)
     (local.get $0)
    )
   )
   (drop
-   (atomic.notify offset=24
+   (memory.atomic.notify offset=24
     (local.get $0)
     (local.get $0)
    )
   )
   (drop
-   (i64.atomic.wait
+   (memory.atomic.wait64
     (local.get $0)
     (local.get $1)
     (local.get $1)
    )
   )
   (drop
-   (i64.atomic.wait offset=16
+   (memory.atomic.wait64 offset=16
     (local.get $0)
     (local.get $1)
     (local.get $1)
diff --git a/binaryen/test/atomics64.wast b/binaryen/test/atomics64.wast
--- a/binaryen/test/atomics64.wast
+++ b/binaryen/test/atomics64.wast
@@ -142,40 +142,40 @@
   (local $1 i64)
   (local $2 i32)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $0)
     (local.get $2)
     (local.get $1)
    )
   )
   (drop
-   (i32.atomic.wait offset=4 align=4
+   (memory.atomic.wait32 offset=4 align=4
     (local.get $0)
     (local.get $2)
     (local.get $1)
    )
   )
   (drop
-   (atomic.notify
+   (memory.atomic.notify
     (local.get $0)
     (local.get $2)
    )
   )
   (drop
-   (atomic.notify offset=24 align=4
+   (memory.atomic.notify offset=24 align=4
     (local.get $0)
     (local.get $2)
    )
   )
   (drop
-   (i64.atomic.wait
+   (memory.atomic.wait64
     (local.get $0)
     (local.get $1)
     (local.get $1)
    )
   )
   (drop
-   (i64.atomic.wait align=8 offset=16
+   (memory.atomic.wait64 align=8 offset=16
     (local.get $0)
     (local.get $1)
     (local.get $1)
diff --git a/binaryen/test/atomics64.wast.from-wast b/binaryen/test/atomics64.wast.from-wast
--- a/binaryen/test/atomics64.wast.from-wast
+++ b/binaryen/test/atomics64.wast.from-wast
@@ -142,40 +142,40 @@
   (local $1 i64)
   (local $2 i32)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $0)
     (local.get $2)
     (local.get $1)
    )
   )
   (drop
-   (i32.atomic.wait offset=4
+   (memory.atomic.wait32 offset=4
     (local.get $0)
     (local.get $2)
     (local.get $1)
    )
   )
   (drop
-   (atomic.notify
+   (memory.atomic.notify
     (local.get $0)
     (local.get $2)
    )
   )
   (drop
-   (atomic.notify offset=24
+   (memory.atomic.notify offset=24
     (local.get $0)
     (local.get $2)
    )
   )
   (drop
-   (i64.atomic.wait
+   (memory.atomic.wait64
     (local.get $0)
     (local.get $1)
     (local.get $1)
    )
   )
   (drop
-   (i64.atomic.wait offset=16
+   (memory.atomic.wait64 offset=16
     (local.get $0)
     (local.get $1)
     (local.get $1)
diff --git a/binaryen/test/atomics64.wast.fromBinary b/binaryen/test/atomics64.wast.fromBinary
--- a/binaryen/test/atomics64.wast.fromBinary
+++ b/binaryen/test/atomics64.wast.fromBinary
@@ -142,40 +142,40 @@
   (local $1 i64)
   (local $2 i64)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $1)
     (local.get $0)
     (local.get $2)
    )
   )
   (drop
-   (i32.atomic.wait offset=4
+   (memory.atomic.wait32 offset=4
     (local.get $1)
     (local.get $0)
     (local.get $2)
    )
   )
   (drop
-   (atomic.notify
+   (memory.atomic.notify
     (local.get $1)
     (local.get $0)
    )
   )
   (drop
-   (atomic.notify offset=24
+   (memory.atomic.notify offset=24
     (local.get $1)
     (local.get $0)
    )
   )
   (drop
-   (i64.atomic.wait
+   (memory.atomic.wait64
     (local.get $1)
     (local.get $2)
     (local.get $2)
    )
   )
   (drop
-   (i64.atomic.wait offset=16
+   (memory.atomic.wait64 offset=16
     (local.get $1)
     (local.get $2)
     (local.get $2)
diff --git a/binaryen/test/atomics64.wast.fromBinary.noDebugInfo b/binaryen/test/atomics64.wast.fromBinary.noDebugInfo
--- a/binaryen/test/atomics64.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/atomics64.wast.fromBinary.noDebugInfo
@@ -142,40 +142,40 @@
   (local $1 i64)
   (local $2 i64)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $1)
     (local.get $0)
     (local.get $2)
    )
   )
   (drop
-   (i32.atomic.wait offset=4
+   (memory.atomic.wait32 offset=4
     (local.get $1)
     (local.get $0)
     (local.get $2)
    )
   )
   (drop
-   (atomic.notify
+   (memory.atomic.notify
     (local.get $1)
     (local.get $0)
    )
   )
   (drop
-   (atomic.notify offset=24
+   (memory.atomic.notify offset=24
     (local.get $1)
     (local.get $0)
    )
   )
   (drop
-   (i64.atomic.wait
+   (memory.atomic.wait64
     (local.get $1)
     (local.get $2)
     (local.get $2)
    )
   )
   (drop
-   (i64.atomic.wait offset=16
+   (memory.atomic.wait64 offset=16
     (local.get $1)
     (local.get $2)
     (local.get $2)
diff --git a/binaryen/test/bad_params.asm.js b/binaryen/test/bad_params.asm.js
deleted file mode 100644
--- a/binaryen/test/bad_params.asm.js
+++ /dev/null
@@ -1,30 +0,0 @@
-function asm(global, env, buffer) {
-  "use asm";
-
-  function missing(x, y) {
-    x = x | 0;
-    y = +y;
-  }
-
-  function extra(x, y) {
-    x = x | 0;
-    y = +y;
-  }
-
-  function mix(a) {
-    a = a | 0;
-  }
-
-  function ex() {
-    missing();
-    missing(1);
-    extra(1, +2, 3);
-    extra(1, +2, 3, 4);
-    mix();
-    mix(1);
-    mix(1, 2);
-  }
-
-  return { ex: ex };
-}
-
diff --git a/binaryen/test/binaryen.js/atomics.js b/binaryen/test/binaryen.js/atomics.js
--- a/binaryen/test/binaryen.js/atomics.js
+++ b/binaryen/test/binaryen.js/atomics.js
@@ -59,21 +59,21 @@
   ),
   // wait and notify
   module.drop(
-    module.i32.atomic.wait(
+    module.memory.atomic.wait32(
       module.i32.const(0),
       module.i32.const(0),
       module.i64.const(0)
     )
   ),
   module.drop(
-    module.i64.atomic.wait(
+    module.memory.atomic.wait64(
       module.i32.const(0),
       module.i64.const(0),
       module.i64.const(0)
     )
   ),
   module.drop(
-    module.atomic.notify(
+    module.memory.atomic.notify(
       module.i32.const(0),
       module.i32.const(0)
     )
diff --git a/binaryen/test/binaryen.js/atomics.js.txt b/binaryen/test/binaryen.js/atomics.js.txt
--- a/binaryen/test/binaryen.js/atomics.js.txt
+++ b/binaryen/test/binaryen.js/atomics.js.txt
@@ -45,21 +45,21 @@
    )
   )
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (i32.const 0)
     (i32.const 0)
     (i64.const 0)
    )
   )
   (drop
-   (i64.atomic.wait
+   (memory.atomic.wait64
     (i32.const 0)
     (i64.const 0)
     (i64.const 0)
    )
   )
   (drop
-   (atomic.notify
+   (memory.atomic.notify
     (i32.const 0)
     (i32.const 0)
    )
diff --git a/binaryen/test/binaryen.js/emit_asmjs.js.txt b/binaryen/test/binaryen.js/emit_asmjs.js.txt
--- a/binaryen/test/binaryen.js/emit_asmjs.js.txt
+++ b/binaryen/test/binaryen.js/emit_asmjs.js.txt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function main($0) {
   $0 = $0 | 0;
   return $0 | 0;
@@ -22,20 +23,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var main = retasmFunc.main;
 
diff --git a/binaryen/test/binaryen.js/exception-handling.js.txt b/binaryen/test/binaryen.js/exception-handling.js.txt
--- a/binaryen/test/binaryen.js/exception-handling.js.txt
+++ b/binaryen/test/binaryen.js/exception-handling.js.txt
@@ -28,7 +28,7 @@
  )
 )
 
-getExpressionInfo(throw) = {"id":45,"type":1,"event":"e"}
-getExpressionInfo(br_on_exn) = {"id":47,"type":9,"name":"l","event":"e"}
-getExpressionInfo(rethrow) = {"id":46,"type":1}
-getExpressionInfo(try) = {"id":44,"type":0}
+getExpressionInfo(throw) = {"id":47,"type":1,"event":"e"}
+getExpressionInfo(br_on_exn) = {"id":49,"type":9,"name":"l","event":"e"}
+getExpressionInfo(rethrow) = {"id":48,"type":1}
+getExpressionInfo(try) = {"id":46,"type":0}
diff --git a/binaryen/test/binaryen.js/expressions.js b/binaryen/test/binaryen.js/expressions.js
--- a/binaryen/test/binaryen.js/expressions.js
+++ b/binaryen/test/binaryen.js/expressions.js
@@ -901,7 +901,7 @@
   var ptr = module.i32.const(2);
   var expected = module.i32.const(3);
   var timeout = module.i64.const(4);
-  const theAtomicWait = binaryen.AtomicWait(module.i32.atomic.wait(ptr, expected, timeout));
+  const theAtomicWait = binaryen.AtomicWait(module.memory.atomic.wait32(ptr, expected, timeout));
   assert(theAtomicWait instanceof binaryen.AtomicWait);
   assert(theAtomicWait instanceof binaryen.Expression);
   assert(theAtomicWait.ptr === ptr);
@@ -926,7 +926,7 @@
   assert(
     theAtomicWait.toText()
     ==
-    "(i64.atomic.wait\n (i32.const 5)\n (i32.const 6)\n (i64.const 7)\n)\n"
+    "(memory.atomic.wait64\n (i32.const 5)\n (i32.const 6)\n (i64.const 7)\n)\n"
   );
 
   module.dispose();
@@ -938,7 +938,7 @@
 
   var ptr = module.i32.const(1);
   var notifyCount = module.i32.const(2);
-  const theAtomicNotify = binaryen.AtomicNotify(module.atomic.notify(ptr, notifyCount));
+  const theAtomicNotify = binaryen.AtomicNotify(module.memory.atomic.notify(ptr, notifyCount));
   assert(theAtomicNotify instanceof binaryen.AtomicNotify);
   assert(theAtomicNotify instanceof binaryen.Expression);
   assert(theAtomicNotify.ptr === ptr);
@@ -957,7 +957,7 @@
   assert(
     theAtomicNotify.toText()
     ==
-    "(atomic.notify\n (i32.const 3)\n (i32.const 4)\n)\n"
+    "(memory.atomic.notify\n (i32.const 3)\n (i32.const 4)\n)\n"
   );
 
   module.dispose();
@@ -1378,7 +1378,7 @@
   const module = new binaryen.Module();
 
   var func = "a";
-  const theRefFunc = binaryen.RefFunc(module.ref.func(func));
+  const theRefFunc = binaryen.RefFunc(module.ref.func(func, binaryen.funcref));
   assert(theRefFunc instanceof binaryen.RefFunc);
   assert(theRefFunc instanceof binaryen.Expression);
   assert(theRefFunc.func === func);
@@ -1388,7 +1388,8 @@
   assert(theRefFunc.func === func);
   theRefFunc.type = binaryen.f64;
   theRefFunc.finalize();
-  assert(theRefFunc.type === binaryen.funcref);
+  // TODO The type is a subtype of funcref, but we can't check that in the JS
+  //      API atm.
 
   console.log(theRefFunc.toText());
   assert(
diff --git a/binaryen/test/binaryen.js/expressions.js.txt b/binaryen/test/binaryen.js/expressions.js.txt
--- a/binaryen/test/binaryen.js/expressions.js.txt
+++ b/binaryen/test/binaryen.js/expressions.js.txt
@@ -128,14 +128,14 @@
 )
 
 # AtomicWait
-(i64.atomic.wait
+(memory.atomic.wait64
  (i32.const 5)
  (i32.const 6)
  (i64.const 7)
 )
 
 # AtomicNotify
-(atomic.notify
+(memory.atomic.notify
  (i32.const 3)
  (i32.const 4)
 )
diff --git a/binaryen/test/binaryen.js/kitchen-sink.js b/binaryen/test/binaryen.js/kitchen-sink.js
--- a/binaryen/test/binaryen.js/kitchen-sink.js
+++ b/binaryen/test/binaryen.js/kitchen-sink.js
@@ -169,6 +169,7 @@
   console.log("TupleExtractId: " + binaryen.TupleExtractId);
   console.log("I31NewId: " + binaryen.I31NewId);
   console.log("I31GetId: " + binaryen.I31GetId);
+  console.log("CallRefId: " + binaryen.CallRefId);
   console.log("RefTestId: " + binaryen.RefTestId);
   console.log("RefCastId: " + binaryen.RefCastId);
   console.log("BrOnCastId: " + binaryen.BrOnCastId);
@@ -280,8 +281,6 @@
     module.i32x4.all_true(module.v128.const(v128_bytes)),
     module.i32x4.bitmask(module.v128.const(v128_bytes)),
     module.i64x2.neg(module.v128.const(v128_bytes)),
-    module.i64x2.any_true(module.v128.const(v128_bytes)),
-    module.i64x2.all_true(module.v128.const(v128_bytes)),
     module.f32x4.abs(module.v128.const(v128_bytes)),
     module.f32x4.neg(module.v128.const(v128_bytes)),
     module.f32x4.sqrt(module.v128.const(v128_bytes)),
@@ -539,8 +538,8 @@
     // Reference types
     module.ref.is_null(module.ref.null(binaryen.externref)),
     module.ref.is_null(module.ref.null(binaryen.funcref)),
-    module.ref.is_null(module.ref.func("kitchen()sinker")),
-    module.select(temp10, module.ref.null(binaryen.funcref), module.ref.func("kitchen()sinker"), binaryen.funcref),
+    module.ref.is_null(module.ref.func("kitchen()sinker", binaryen.funcref)),
+    module.select(temp10, module.ref.null(binaryen.funcref), module.ref.func("kitchen()sinker", binaryen.funcref), binaryen.funcref),
 
     // GC
     module.ref.eq(module.ref.null(binaryen.eqref), module.ref.null(binaryen.eqref)),
@@ -570,14 +569,14 @@
       )
     ),
     module.drop(
-      module.i32.atomic.wait(
+      module.memory.atomic.wait32(
         module.i32.const(0),
         module.i32.const(0),
         module.i64.const(0)
       )
     ),
     module.drop(
-      module.atomic.notify(
+      module.memory.atomic.notify(
         module.i32.const(0),
         module.i32.const(0)
       )
@@ -1034,7 +1033,16 @@
   var expected_data = ["hello, world", "segment data 2"];
   var expected_passive = [false, false];
 
-  var global = module.addGlobal("a-global", binaryen.i32, false, module.i32.const(expected_offsets[1]))
+  var glos = [
+    module.addGlobal("a-global", binaryen.i32, false, module.i32.const(expected_offsets[1])),
+    module.addGlobal("a-global2", binaryen.i32, false, module.i32.const(2)),
+    module.addGlobal("a-global3", binaryen.i32, false, module.i32.const(3))
+  ];
+
+  for (i = 0; i < module.getNumGlobals(); i++) {
+    assert(module.getGlobalByIndex(i) === glos[i]);
+  }
+
   module.setMemory(1, 256, "mem", [
     {
       passive: expected_passive[0],
diff --git a/binaryen/test/binaryen.js/kitchen-sink.js.txt b/binaryen/test/binaryen.js/kitchen-sink.js.txt
--- a/binaryen/test/binaryen.js/kitchen-sink.js.txt
+++ b/binaryen/test/binaryen.js/kitchen-sink.js.txt
@@ -41,7 +41,7 @@
 Features.Multivalue: 512
 Features.GC: 1024
 Features.Memory64: 2048
-Features.All: 4095
+Features.All: 8191
 InvalidId: 0
 BlockId: 1
 IfId: 2
@@ -65,46 +65,47 @@
 MemorySizeId: 20
 MemoryGrowId: 21
 NopId: 22
-UnreachableId: 23
-AtomicCmpxchgId: 25
-AtomicRMWId: 24
-AtomicWaitId: 26
-AtomicNotifyId: 27
-SIMDExtractId: 29
-SIMDReplaceId: 30
-SIMDShuffleId: 31
-SIMDTernaryId: 32
-SIMDShiftId: 33
-SIMDLoadId: 34
-MemoryInitId: 35
-DataDropId: 36
-MemoryCopyId: 37
-MemoryFillId: 38
-PopId: 39
-RefNullId: 40
-RefIsNullId: 41
-RefFuncId: 42
-RefEqId: 43
-TryId: 44
-ThrowId: 45
-RethrowId: 46
-BrOnExnId: 47
-TupleMakeId: 48
-TupleExtractId: 49
-I31NewId: 50
-I31GetId: 51
-RefTestId: 52
-RefCastId: 53
-BrOnCastId: 54
-RttCanonId: 55
-RttSubId: 56
-StructNewId: 57
-StructGetId: 58
-StructSetId: 59
-ArrayNewId: 60
-ArrayGetId: 61
-ArraySetId: 62
-ArrayLenId: 63
+UnreachableId: 24
+AtomicCmpxchgId: 26
+AtomicRMWId: 25
+AtomicWaitId: 27
+AtomicNotifyId: 28
+SIMDExtractId: 30
+SIMDReplaceId: 31
+SIMDShuffleId: 32
+SIMDTernaryId: 33
+SIMDShiftId: 34
+SIMDLoadId: 35
+MemoryInitId: 37
+DataDropId: 38
+MemoryCopyId: 39
+MemoryFillId: 40
+PopId: 41
+RefNullId: 42
+RefIsNullId: 43
+RefFuncId: 44
+RefEqId: 45
+TryId: 46
+ThrowId: 47
+RethrowId: 48
+BrOnExnId: 49
+TupleMakeId: 50
+TupleExtractId: 51
+I31NewId: 52
+I31GetId: 53
+CallRefId: 54
+RefTestId: 55
+RefCastId: 56
+BrOnCastId: 57
+RttCanonId: 58
+RttSubId: 59
+StructNewId: 60
+StructGetId: 61
+StructSetId: 62
+ArrayNewId: 63
+ArrayGetId: 64
+ArraySetId: 65
+ArrayLenId: 66
 getExpressionInfo={"id":15,"type":4,"op":6}
 (f32.neg
  (f32.const -33.61199951171875)
@@ -482,16 +483,6 @@
        )
       )
       (drop
-       (i64x2.any_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.all_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
        (f32x4.abs
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
@@ -1896,14 +1887,14 @@
        )
       )
       (drop
-       (i32.atomic.wait
+       (memory.atomic.wait32
         (i32.const 0)
         (i32.const 0)
         (i64.const 0)
        )
       )
       (drop
-       (atomic.notify
+       (memory.atomic.notify
         (i32.const 0)
         (i32.const 0)
        )
@@ -2364,16 +2355,6 @@
        )
       )
       (drop
-       (i64x2.any_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.all_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
        (f32x4.abs
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
@@ -3778,14 +3759,14 @@
        )
       )
       (drop
-       (i32.atomic.wait
+       (memory.atomic.wait32
         (i32.const 0)
         (i32.const 0)
         (i64.const 0)
        )
       )
       (drop
-       (atomic.notify
+       (memory.atomic.notify
         (i32.const 0)
         (i32.const 0)
        )
@@ -4390,8 +4371,8 @@
 )
 
 [wasm-validator error in function func] local.set's value type must be correct, on 
-[none] (local.set $0
- [i64] (i64.const 1234)
+(local.set $0
+ (i64.const 1234)
 )
 validation: 0
 test_parsing text:
@@ -4431,6 +4412,8 @@
  (table $0 1 funcref)
  (elem (i32.const 0) $fn0 $fn1 $fn2)
  (global $a-global i32 (i32.const 125))
+ (global $a-global2 i32 (i32.const 2))
+ (global $a-global3 i32 (i32.const 3))
  (export "export0" (func $fn0))
  (export "export1" (func $fn1))
  (export "export2" (func $fn2))
diff --git a/binaryen/test/binaryen.js/validation_errors.js.txt b/binaryen/test/binaryen.js/validation_errors.js.txt
--- a/binaryen/test/binaryen.js/validation_errors.js.txt
+++ b/binaryen/test/binaryen.js/validation_errors.js.txt
@@ -1,6 +1,6 @@
 [wasm-validator error in function test] unexpected false: global.get name must be valid, on 
-[i32] (global.get $missing)
+(global.get $missing)
 0
 [wasm-validator error in function test] unexpected false: local.get index must be small enough, on 
-[i32] (local.get $0)
+(local.get $0)
 0
diff --git a/binaryen/test/debugInfo.asm.js b/binaryen/test/debugInfo.asm.js
deleted file mode 100644
--- a/binaryen/test/debugInfo.asm.js
+++ /dev/null
@@ -1,102 +0,0 @@
-function () {
-  "use asm";
-  var STACKTOP = 0;
-  function add(x, y) {
-    x = x | 0;
-    y = y | 0;
-    x = x; //@line 5 "tests/hello_world.c"
-    y = y; //@line 6 "tests/hello_world.c"
-    x = y; //@line 314159 "tests/other_file.cpp"
-    return x + y | 0;
-  }
-  function ret(x) {
-    x = x | 0;
-    x = x << 1; //@line 50 "return.cpp"
-    return x + 1 | 0; //@line 100 "return.cpp"
-  }
-  function opts(x, y) {
-    x = x | 0;
-    y = y | 0;
-    x = (x + y) | 0; //@line 1 "even-opted.cpp"
-    y = y >> x; //@line 2 "even-opted.cpp"
-    x = (x | 0) % (y | 0); //@line 3 "even-opted.cpp"
-    return x + y | 0;
-  }
-  function fib($0) {
-   $0 = $0|0;
-   var $$0$lcssa = 0, $$01518 = 0, $$01518$phi = 0, $$01617 = 0, $$019 = 0, $1 = 0, $2 = 0, $3 = 0, $exitcond = 0, label = 0, sp = 0;
-   sp = STACKTOP;
-   $1 = ($0|0)>(0); //@line 3 "fib.c"
-   if ($1) {
-    $$01518 = 0;$$01617 = 0;$$019 = 1;
-   } else {
-    $$0$lcssa = 1;
-    return ($$0$lcssa|0); //@line 8 "fib.c"
-   }
-   while(1) {
-    $2 = (($$019) + ($$01518))|0; //@line 4 "fib.c"
-    $3 = (($$01617) + 1)|0; //@line 3 "fib.c"
-    $exitcond = ($3|0)==($0|0); //@line 3 "fib.c"
-    if ($exitcond) {
-     $$0$lcssa = $2;
-     break;
-    } else {
-     $$01518$phi = $$019;$$01617 = $3;$$019 = $2;$$01518 = $$01518$phi;
-    }
-   }
-   return ($$0$lcssa|0); //@line 8 "fib.c"
-  }
-  function switch_reach($p) {
-   $p = $p|0;
-   var $0 = 0, $call = 0, $magic = 0, $rc$0 = 0, $switch$split2D = 0, label = 0, sp = 0;
-   sp = STACKTOP;
-   $magic = ((($p)) + 52|0);
-   $0 = $magic;
-   $switch$split2D = ($0|0)<(1369188723);
-   if ($switch$split2D) {
-    switch ($0|0) {
-    case -1108210269:  {
-     label = 2;
-     break;
-    }
-    default: {
-     $rc$0 = 0;
-    }
-    }
-   } else {
-    switch ($0|0) {
-    case 1369188723:  {
-     label = 2;
-     break;
-    }
-    default: {
-     $rc$0 = 0;
-    }
-    }
-   }
-   if ((label|0) == 2) {
-    $call = switch_reach($p) | 0;
-    $rc$0 = $call;
-   }
-   switch_reach($p) | 0;
-   return ($rc$0|0); //@line 59950 "/tmp/emscripten_test_binaryen2_28hnAe/src.c"
-  }
-  function nofile() {
-    nofile(); //@line 1337
-  }
-  function inlineMe(x, y) {
-    x = x | 0;
-    y = y | 0;
-    x = x + y | 0; //@line 120 "inline_me.c"
-    y = x + y | 0; //@line 121 "inline_me.c"
-    x = x + y | 0; //@line 122 "inline_me.c"
-    return x | 0; //@line 123 "inline_me.c"
-  }
-  function inlineInto(x, y) {
-    x = x | 0;
-    y = y | 0;
-    return inlineMe(x | 0, y | 0) | 0; //@line 125 "inline_me.c"
-  }
-  return { add: add, ret: ret, opts: opts, fib: fib, switch_reach: switch_reach, nofile: nofile, inlineInto: inlineInto };
-}
-
diff --git a/binaryen/test/dylib.wasm.fromBinary b/binaryen/test/dylib.wasm.fromBinary
--- a/binaryen/test/dylib.wasm.fromBinary
+++ b/binaryen/test/dylib.wasm.fromBinary
@@ -3,9 +3,9 @@
  (type $none_=>_none (func))
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
- (import "env" "memory" (memory $mimport$5 0))
- (data (global.get $gimport$4) "*\00\00\00")
- (import "env" "__memory_base" (global $gimport$4 i32))
+ (import "env" "memory" (memory $mimport$0 0))
+ (data (global.get $gimport$0) "*\00\00\00")
+ (import "env" "__memory_base" (global $gimport$0 i32))
  (import "env" "g$waka_mine" (func $fimport$0 (result i32)))
  (import "env" "g$waka_others" (func $fimport$1 (result i32)))
  (import "env" "fp$_Z16waka_func_theirsi$ii" (func $fimport$2 (result i32)))
diff --git a/binaryen/test/dynamicLibrary.asm.js b/binaryen/test/dynamicLibrary.asm.js
deleted file mode 100644
--- a/binaryen/test/dynamicLibrary.asm.js
+++ /dev/null
@@ -1,136 +0,0 @@
-Module["asm"] =  (function(global, env, buffer) {
-  'almost asm';
-  
-  
-  var HEAP8 = new global.Int8Array(buffer);
-  var HEAP16 = new global.Int16Array(buffer);
-  var HEAP32 = new global.Int32Array(buffer);
-  var HEAPU8 = new global.Uint8Array(buffer);
-  var HEAPU16 = new global.Uint16Array(buffer);
-  var HEAPU32 = new global.Uint32Array(buffer);
-  var HEAPF32 = new global.Float32Array(buffer);
-  var HEAPF64 = new global.Float64Array(buffer);
-
-
-  var DYNAMICTOP_PTR=env.DYNAMICTOP_PTR|0;
-  var tempDoublePtr=env.tempDoublePtr|0;
-  var ABORT=env.ABORT|0;
-  var memoryBase=env.memoryBase|0;
-  var tableBase=env.tableBase|0;
-
-  var STACKTOP = 0, STACK_MAX = 0;
-
-  var __THREW__ = 0;
-  var threwValue = 0;
-  var setjmpId = 0;
-  var undef = 0;
-  var nan = global.NaN, inf = global.Infinity;
-  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
-  var tempRet0 = 0;
-
-  var Math_floor=global.Math.floor;
-  var Math_abs=global.Math.abs;
-  var Math_sqrt=global.Math.sqrt;
-  var Math_pow=global.Math.pow;
-  var Math_cos=global.Math.cos;
-  var Math_sin=global.Math.sin;
-  var Math_tan=global.Math.tan;
-  var Math_acos=global.Math.acos;
-  var Math_asin=global.Math.asin;
-  var Math_atan=global.Math.atan;
-  var Math_atan2=global.Math.atan2;
-  var Math_exp=global.Math.exp;
-  var Math_log=global.Math.log;
-  var Math_ceil=global.Math.ceil;
-  var Math_imul=global.Math.imul;
-  var Math_min=global.Math.min;
-  var Math_max=global.Math.max;
-  var Math_clz32=global.Math.clz32;
-  var Math_fround=global.Math.fround;
-  var abort=env.abort;
-  var assert=env.assert;
-  var enlargeMemory=env.enlargeMemory;
-  var getTotalMemory=env.getTotalMemory;
-  var abortOnCannotGrowMemory=env.abortOnCannotGrowMemory;
-  var abortStackOverflow=env.abortStackOverflow;
-  var setTempRet0=env.setTempRet0;
-  var getTempRet0=env.getTempRet0;
-  var _puts=env._puts;
-  var tempFloat = Math_fround(0);
-  const f0 = Math_fround(0);
-
-// EMSCRIPTEN_START_FUNCS
-
-function stackAlloc(size) {
-  size = size|0;
-  var ret = 0;
-  ret = STACKTOP;
-  STACKTOP = (STACKTOP + size)|0;
-  STACKTOP = (STACKTOP + 15)&-16;
-  if ((STACKTOP|0) >= (STACK_MAX|0)) abortStackOverflow(size|0);
-
-  return ret|0;
-}
-function stackSave() {
-  return STACKTOP|0;
-}
-function stackRestore(top) {
-  top = top|0;
-  STACKTOP = top;
-}
-function establishStackSpace(stackBase, stackMax) {
-  stackBase = stackBase|0;
-  stackMax = stackMax|0;
-  STACKTOP = stackBase;
-  STACK_MAX = stackMax;
-}
-
-function setThrew(threw, value) {
-  threw = threw|0;
-  value = value|0;
-  if ((__THREW__|0) == 0) {
-    __THREW__ = threw;
-    threwValue = value;
-  }
-}
-
-function ___cxx_global_var_init() {
- var label = 0, sp = 0;
- sp = STACKTOP;
- __ZN3FooC2Ev((memoryBase + (5242912) | 0));
- return;
-}
-function __ZN3FooC2Ev($0) {
- $0 = $0|0;
- var $1 = 0, label = 0, sp = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 16|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abortStackOverflow(16|0);
- $1 = $0;
- (_puts(((memoryBase + (0) | 0)|0))|0);
- STACKTOP = sp;return;
-}
-function __GLOBAL__sub_I_liblib_cpp() {
- var label = 0, sp = 0;
- sp = STACKTOP;
- ___cxx_global_var_init();
- return;
-}
-function runPostSets() {
- var temp = 0;
-}
-function __post_instantiate() {
- STACKTOP = (memoryBase + (32) | 0);
- STACK_MAX = STACKTOP + 5242880 | 0;
- runPostSets();
- __GLOBAL__sub_I_liblib_cpp();
-}
-
-  
-
-
-// EMSCRIPTEN_END_FUNCS
-
-
-  return { __ZN3FooC2Ev: __ZN3FooC2Ev, __post_instantiate: __post_instantiate, runPostSets: runPostSets, _global: 5242912 };
-})
-;
diff --git a/binaryen/test/emcc_O2_hello_world.asm.js b/binaryen/test/emcc_O2_hello_world.asm.js
deleted file mode 100644
--- a/binaryen/test/emcc_O2_hello_world.asm.js
+++ /dev/null
@@ -1,2293 +0,0 @@
-Module["asm"] =  (function(global,env,buffer) {
-
-  'use asm';
-  
-  
-  var HEAP8 = new global.Int8Array(buffer);
-  var HEAP16 = new global.Int16Array(buffer);
-  var HEAP32 = new global.Int32Array(buffer);
-  var HEAPU8 = new global.Uint8Array(buffer);
-  var HEAPU16 = new global.Uint16Array(buffer);
-  var HEAPU32 = new global.Uint32Array(buffer);
-  var HEAPF32 = new global.Float32Array(buffer);
-  var HEAPF64 = new global.Float64Array(buffer);
-
-
-  var STACKTOP=env.STACKTOP|0;
-  var STACK_MAX=env.STACK_MAX|0;
-  var tempDoublePtr=env.tempDoublePtr|0;
-  var ABORT=env.ABORT|0;
-
-  var __THREW__ = 0;
-  var threwValue = 0;
-  var setjmpId = 0;
-  var undef = 0;
-  var nan = global.NaN, inf = global.Infinity;
-  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
-
-  var tempRet0 = 0;
-  var tempRet1 = 0;
-  var tempRet2 = 0;
-  var tempRet3 = 0;
-  var tempRet4 = 0;
-  var tempRet5 = 0;
-  var tempRet6 = 0;
-  var tempRet7 = 0;
-  var tempRet8 = 0;
-  var tempRet9 = 0;
-  var Math_floor=global.Math.floor;
-  var Math_abs=global.Math.abs;
-  var Math_sqrt=global.Math.sqrt;
-  var Math_pow=global.Math.pow;
-  var Math_cos=global.Math.cos;
-  var Math_sin=global.Math.sin;
-  var Math_tan=global.Math.tan;
-  var Math_acos=global.Math.acos;
-  var Math_asin=global.Math.asin;
-  var Math_atan=global.Math.atan;
-  var Math_atan2=global.Math.atan2;
-  var Math_exp=global.Math.exp;
-  var Math_log=global.Math.log;
-  var Math_ceil=global.Math.ceil;
-  var Math_imul=global.Math.imul;
-  var Math_min=global.Math.min;
-  var Math_clz32=global.Math.clz32;
-  var abort=env.abort;
-  var assert=env.assert;
-  var invoke_ii=env.invoke_ii;
-  var invoke_iiii=env.invoke_iiii;
-  var invoke_vi=env.invoke_vi;
-  var _pthread_cleanup_pop=env._pthread_cleanup_pop;
-  var _pthread_self=env._pthread_self;
-  var _sysconf=env._sysconf;
-  var ___lock=env.___lock;
-  var ___syscall6=env.___syscall6;
-  var ___setErrNo=env.___setErrNo;
-  var _abort=env._abort;
-  var _sbrk=env._sbrk;
-  var _time=env._time;
-  var _pthread_cleanup_push=env._pthread_cleanup_push;
-  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
-  var ___syscall54=env.___syscall54;
-  var ___unlock=env.___unlock;
-  var ___syscall140=env.___syscall140;
-  var _emscripten_set_main_loop_timing=env._emscripten_set_main_loop_timing;
-  var _emscripten_set_main_loop=env._emscripten_set_main_loop;
-  var ___syscall146=env.___syscall146;
-  var tempFloat = 0.0;
-
-// EMSCRIPTEN_START_FUNCS
-
-function _malloc(i1) {
- i1 = i1 | 0;
- var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0, i38 = 0, i39 = 0, i40 = 0, i41 = 0, i42 = 0, i43 = 0, i44 = 0, i45 = 0, i46 = 0, i47 = 0, i48 = 0, i49 = 0, i50 = 0, i51 = 0, i52 = 0, i53 = 0, i54 = 0, i55 = 0, i56 = 0, i57 = 0, i58 = 0, i59 = 0, i60 = 0, i61 = 0, i62 = 0, i63 = 0, i64 = 0, i65 = 0, i66 = 0, i67 = 0, i68 = 0, i69 = 0, i70 = 0, i71 = 0, i72 = 0, i73 = 0, i74 = 0, i75 = 0, i76 = 0, i77 = 0, i78 = 0, i79 = 0, i80 = 0, i81 = 0, i82 = 0, i83 = 0, i84 = 0, i85 = 0, i86 = 0, i87 = 0, i88 = 0, i89 = 0, i90 = 0, i91 = 0, i92 = 0;
- do if (i1 >>> 0 < 245) {
-  i2 = i1 >>> 0 < 11 ? 16 : i1 + 11 & -8;
-  i3 = i2 >>> 3;
-  i4 = HEAP32[44] | 0;
-  i5 = i4 >>> i3;
-  if (i5 & 3) {
-   i6 = (i5 & 1 ^ 1) + i3 | 0;
-   i7 = 216 + (i6 << 1 << 2) | 0;
-   i8 = i7 + 8 | 0;
-   i9 = HEAP32[i8 >> 2] | 0;
-   i10 = i9 + 8 | 0;
-   i11 = HEAP32[i10 >> 2] | 0;
-   do if ((i7 | 0) != (i11 | 0)) {
-    if (i11 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-    i12 = i11 + 12 | 0;
-    if ((HEAP32[i12 >> 2] | 0) == (i9 | 0)) {
-     HEAP32[i12 >> 2] = i7;
-     HEAP32[i8 >> 2] = i11;
-     break;
-    } else _abort();
-   } else HEAP32[44] = i4 & ~(1 << i6); while (0);
-   i11 = i6 << 3;
-   HEAP32[i9 + 4 >> 2] = i11 | 3;
-   i8 = i9 + i11 + 4 | 0;
-   HEAP32[i8 >> 2] = HEAP32[i8 >> 2] | 1;
-   i13 = i10;
-   return i13 | 0;
-  }
-  i8 = HEAP32[46] | 0;
-  if (i2 >>> 0 > i8 >>> 0) {
-   if (i5) {
-    i11 = 2 << i3;
-    i7 = i5 << i3 & (i11 | 0 - i11);
-    i11 = (i7 & 0 - i7) + -1 | 0;
-    i7 = i11 >>> 12 & 16;
-    i12 = i11 >>> i7;
-    i11 = i12 >>> 5 & 8;
-    i14 = i12 >>> i11;
-    i12 = i14 >>> 2 & 4;
-    i15 = i14 >>> i12;
-    i14 = i15 >>> 1 & 2;
-    i16 = i15 >>> i14;
-    i15 = i16 >>> 1 & 1;
-    i17 = (i11 | i7 | i12 | i14 | i15) + (i16 >>> i15) | 0;
-    i15 = 216 + (i17 << 1 << 2) | 0;
-    i16 = i15 + 8 | 0;
-    i14 = HEAP32[i16 >> 2] | 0;
-    i12 = i14 + 8 | 0;
-    i7 = HEAP32[i12 >> 2] | 0;
-    do if ((i15 | 0) != (i7 | 0)) {
-     if (i7 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-     i11 = i7 + 12 | 0;
-     if ((HEAP32[i11 >> 2] | 0) == (i14 | 0)) {
-      HEAP32[i11 >> 2] = i15;
-      HEAP32[i16 >> 2] = i7;
-      i18 = HEAP32[46] | 0;
-      break;
-     } else _abort();
-    } else {
-     HEAP32[44] = i4 & ~(1 << i17);
-     i18 = i8;
-    } while (0);
-    i8 = (i17 << 3) - i2 | 0;
-    HEAP32[i14 + 4 >> 2] = i2 | 3;
-    i4 = i14 + i2 | 0;
-    HEAP32[i4 + 4 >> 2] = i8 | 1;
-    HEAP32[i4 + i8 >> 2] = i8;
-    if (i18) {
-     i7 = HEAP32[49] | 0;
-     i16 = i18 >>> 3;
-     i15 = 216 + (i16 << 1 << 2) | 0;
-     i3 = HEAP32[44] | 0;
-     i5 = 1 << i16;
-     if (i3 & i5) {
-      i16 = i15 + 8 | 0;
-      i10 = HEAP32[i16 >> 2] | 0;
-      if (i10 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-       i19 = i16;
-       i20 = i10;
-      }
-     } else {
-      HEAP32[44] = i3 | i5;
-      i19 = i15 + 8 | 0;
-      i20 = i15;
-     }
-     HEAP32[i19 >> 2] = i7;
-     HEAP32[i20 + 12 >> 2] = i7;
-     HEAP32[i7 + 8 >> 2] = i20;
-     HEAP32[i7 + 12 >> 2] = i15;
-    }
-    HEAP32[46] = i8;
-    HEAP32[49] = i4;
-    i13 = i12;
-    return i13 | 0;
-   }
-   i4 = HEAP32[45] | 0;
-   if (i4) {
-    i8 = (i4 & 0 - i4) + -1 | 0;
-    i4 = i8 >>> 12 & 16;
-    i15 = i8 >>> i4;
-    i8 = i15 >>> 5 & 8;
-    i7 = i15 >>> i8;
-    i15 = i7 >>> 2 & 4;
-    i5 = i7 >>> i15;
-    i7 = i5 >>> 1 & 2;
-    i3 = i5 >>> i7;
-    i5 = i3 >>> 1 & 1;
-    i10 = HEAP32[480 + ((i8 | i4 | i15 | i7 | i5) + (i3 >>> i5) << 2) >> 2] | 0;
-    i5 = (HEAP32[i10 + 4 >> 2] & -8) - i2 | 0;
-    i3 = i10;
-    i7 = i10;
-    while (1) {
-     i10 = HEAP32[i3 + 16 >> 2] | 0;
-     if (!i10) {
-      i15 = HEAP32[i3 + 20 >> 2] | 0;
-      if (!i15) {
-       i21 = i5;
-       i22 = i7;
-       break;
-      } else i23 = i15;
-     } else i23 = i10;
-     i10 = (HEAP32[i23 + 4 >> 2] & -8) - i2 | 0;
-     i15 = i10 >>> 0 < i5 >>> 0;
-     i5 = i15 ? i10 : i5;
-     i3 = i23;
-     i7 = i15 ? i23 : i7;
-    }
-    i7 = HEAP32[48] | 0;
-    if (i22 >>> 0 < i7 >>> 0) _abort();
-    i3 = i22 + i2 | 0;
-    if (i22 >>> 0 >= i3 >>> 0) _abort();
-    i5 = HEAP32[i22 + 24 >> 2] | 0;
-    i12 = HEAP32[i22 + 12 >> 2] | 0;
-    do if ((i12 | 0) == (i22 | 0)) {
-     i14 = i22 + 20 | 0;
-     i17 = HEAP32[i14 >> 2] | 0;
-     if (!i17) {
-      i15 = i22 + 16 | 0;
-      i10 = HEAP32[i15 >> 2] | 0;
-      if (!i10) {
-       i24 = 0;
-       break;
-      } else {
-       i25 = i10;
-       i26 = i15;
-      }
-     } else {
-      i25 = i17;
-      i26 = i14;
-     }
-     while (1) {
-      i14 = i25 + 20 | 0;
-      i17 = HEAP32[i14 >> 2] | 0;
-      if (i17) {
-       i25 = i17;
-       i26 = i14;
-       continue;
-      }
-      i14 = i25 + 16 | 0;
-      i17 = HEAP32[i14 >> 2] | 0;
-      if (!i17) {
-       i27 = i25;
-       i28 = i26;
-       break;
-      } else {
-       i25 = i17;
-       i26 = i14;
-      }
-     }
-     if (i28 >>> 0 < i7 >>> 0) _abort(); else {
-      HEAP32[i28 >> 2] = 0;
-      i24 = i27;
-      break;
-     }
-    } else {
-     i14 = HEAP32[i22 + 8 >> 2] | 0;
-     if (i14 >>> 0 < i7 >>> 0) _abort();
-     i17 = i14 + 12 | 0;
-     if ((HEAP32[i17 >> 2] | 0) != (i22 | 0)) _abort();
-     i15 = i12 + 8 | 0;
-     if ((HEAP32[i15 >> 2] | 0) == (i22 | 0)) {
-      HEAP32[i17 >> 2] = i12;
-      HEAP32[i15 >> 2] = i14;
-      i24 = i12;
-      break;
-     } else _abort();
-    } while (0);
-    do if (i5) {
-     i12 = HEAP32[i22 + 28 >> 2] | 0;
-     i7 = 480 + (i12 << 2) | 0;
-     if ((i22 | 0) == (HEAP32[i7 >> 2] | 0)) {
-      HEAP32[i7 >> 2] = i24;
-      if (!i24) {
-       HEAP32[45] = HEAP32[45] & ~(1 << i12);
-       break;
-      }
-     } else {
-      if (i5 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-      i12 = i5 + 16 | 0;
-      if ((HEAP32[i12 >> 2] | 0) == (i22 | 0)) HEAP32[i12 >> 2] = i24; else HEAP32[i5 + 20 >> 2] = i24;
-      if (!i24) break;
-     }
-     i12 = HEAP32[48] | 0;
-     if (i24 >>> 0 < i12 >>> 0) _abort();
-     HEAP32[i24 + 24 >> 2] = i5;
-     i7 = HEAP32[i22 + 16 >> 2] | 0;
-     do if (i7) if (i7 >>> 0 < i12 >>> 0) _abort(); else {
-      HEAP32[i24 + 16 >> 2] = i7;
-      HEAP32[i7 + 24 >> 2] = i24;
-      break;
-     } while (0);
-     i7 = HEAP32[i22 + 20 >> 2] | 0;
-     if (i7) if (i7 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-      HEAP32[i24 + 20 >> 2] = i7;
-      HEAP32[i7 + 24 >> 2] = i24;
-      break;
-     }
-    } while (0);
-    if (i21 >>> 0 < 16) {
-     i5 = i21 + i2 | 0;
-     HEAP32[i22 + 4 >> 2] = i5 | 3;
-     i7 = i22 + i5 + 4 | 0;
-     HEAP32[i7 >> 2] = HEAP32[i7 >> 2] | 1;
-    } else {
-     HEAP32[i22 + 4 >> 2] = i2 | 3;
-     HEAP32[i3 + 4 >> 2] = i21 | 1;
-     HEAP32[i3 + i21 >> 2] = i21;
-     i7 = HEAP32[46] | 0;
-     if (i7) {
-      i5 = HEAP32[49] | 0;
-      i12 = i7 >>> 3;
-      i7 = 216 + (i12 << 1 << 2) | 0;
-      i14 = HEAP32[44] | 0;
-      i15 = 1 << i12;
-      if (i14 & i15) {
-       i12 = i7 + 8 | 0;
-       i17 = HEAP32[i12 >> 2] | 0;
-       if (i17 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-        i29 = i12;
-        i30 = i17;
-       }
-      } else {
-       HEAP32[44] = i14 | i15;
-       i29 = i7 + 8 | 0;
-       i30 = i7;
-      }
-      HEAP32[i29 >> 2] = i5;
-      HEAP32[i30 + 12 >> 2] = i5;
-      HEAP32[i5 + 8 >> 2] = i30;
-      HEAP32[i5 + 12 >> 2] = i7;
-     }
-     HEAP32[46] = i21;
-     HEAP32[49] = i3;
-    }
-    i13 = i22 + 8 | 0;
-    return i13 | 0;
-   } else i31 = i2;
-  } else i31 = i2;
- } else if (i1 >>> 0 <= 4294967231) {
-  i7 = i1 + 11 | 0;
-  i5 = i7 & -8;
-  i15 = HEAP32[45] | 0;
-  if (i15) {
-   i14 = 0 - i5 | 0;
-   i17 = i7 >>> 8;
-   if (i17) if (i5 >>> 0 > 16777215) i32 = 31; else {
-    i7 = (i17 + 1048320 | 0) >>> 16 & 8;
-    i12 = i17 << i7;
-    i17 = (i12 + 520192 | 0) >>> 16 & 4;
-    i10 = i12 << i17;
-    i12 = (i10 + 245760 | 0) >>> 16 & 2;
-    i4 = 14 - (i17 | i7 | i12) + (i10 << i12 >>> 15) | 0;
-    i32 = i5 >>> (i4 + 7 | 0) & 1 | i4 << 1;
-   } else i32 = 0;
-   i4 = HEAP32[480 + (i32 << 2) >> 2] | 0;
-   L123 : do if (!i4) {
-    i33 = i14;
-    i34 = 0;
-    i35 = 0;
-    i36 = 86;
-   } else {
-    i12 = i14;
-    i10 = 0;
-    i7 = i5 << ((i32 | 0) == 31 ? 0 : 25 - (i32 >>> 1) | 0);
-    i17 = i4;
-    i8 = 0;
-    while (1) {
-     i16 = HEAP32[i17 + 4 >> 2] & -8;
-     i9 = i16 - i5 | 0;
-     if (i9 >>> 0 < i12 >>> 0) if ((i16 | 0) == (i5 | 0)) {
-      i37 = i9;
-      i38 = i17;
-      i39 = i17;
-      i36 = 90;
-      break L123;
-     } else {
-      i40 = i9;
-      i41 = i17;
-     } else {
-      i40 = i12;
-      i41 = i8;
-     }
-     i9 = HEAP32[i17 + 20 >> 2] | 0;
-     i17 = HEAP32[i17 + 16 + (i7 >>> 31 << 2) >> 2] | 0;
-     i16 = (i9 | 0) == 0 | (i9 | 0) == (i17 | 0) ? i10 : i9;
-     i9 = (i17 | 0) == 0;
-     if (i9) {
-      i33 = i40;
-      i34 = i16;
-      i35 = i41;
-      i36 = 86;
-      break;
-     } else {
-      i12 = i40;
-      i10 = i16;
-      i7 = i7 << (i9 & 1 ^ 1);
-      i8 = i41;
-     }
-    }
-   } while (0);
-   if ((i36 | 0) == 86) {
-    if ((i34 | 0) == 0 & (i35 | 0) == 0) {
-     i4 = 2 << i32;
-     i14 = i15 & (i4 | 0 - i4);
-     if (!i14) {
-      i31 = i5;
-      break;
-     }
-     i4 = (i14 & 0 - i14) + -1 | 0;
-     i14 = i4 >>> 12 & 16;
-     i2 = i4 >>> i14;
-     i4 = i2 >>> 5 & 8;
-     i3 = i2 >>> i4;
-     i2 = i3 >>> 2 & 4;
-     i8 = i3 >>> i2;
-     i3 = i8 >>> 1 & 2;
-     i7 = i8 >>> i3;
-     i8 = i7 >>> 1 & 1;
-     i42 = HEAP32[480 + ((i4 | i14 | i2 | i3 | i8) + (i7 >>> i8) << 2) >> 2] | 0;
-    } else i42 = i34;
-    if (!i42) {
-     i43 = i33;
-     i44 = i35;
-    } else {
-     i37 = i33;
-     i38 = i42;
-     i39 = i35;
-     i36 = 90;
-    }
-   }
-   if ((i36 | 0) == 90) while (1) {
-    i36 = 0;
-    i8 = (HEAP32[i38 + 4 >> 2] & -8) - i5 | 0;
-    i7 = i8 >>> 0 < i37 >>> 0;
-    i3 = i7 ? i8 : i37;
-    i8 = i7 ? i38 : i39;
-    i7 = HEAP32[i38 + 16 >> 2] | 0;
-    if (i7) {
-     i37 = i3;
-     i38 = i7;
-     i39 = i8;
-     i36 = 90;
-     continue;
-    }
-    i38 = HEAP32[i38 + 20 >> 2] | 0;
-    if (!i38) {
-     i43 = i3;
-     i44 = i8;
-     break;
-    } else {
-     i37 = i3;
-     i39 = i8;
-     i36 = 90;
-    }
-   }
-   if ((i44 | 0) != 0 ? i43 >>> 0 < ((HEAP32[46] | 0) - i5 | 0) >>> 0 : 0) {
-    i15 = HEAP32[48] | 0;
-    if (i44 >>> 0 < i15 >>> 0) _abort();
-    i8 = i44 + i5 | 0;
-    if (i44 >>> 0 >= i8 >>> 0) _abort();
-    i3 = HEAP32[i44 + 24 >> 2] | 0;
-    i7 = HEAP32[i44 + 12 >> 2] | 0;
-    do if ((i7 | 0) == (i44 | 0)) {
-     i2 = i44 + 20 | 0;
-     i14 = HEAP32[i2 >> 2] | 0;
-     if (!i14) {
-      i4 = i44 + 16 | 0;
-      i10 = HEAP32[i4 >> 2] | 0;
-      if (!i10) {
-       i45 = 0;
-       break;
-      } else {
-       i46 = i10;
-       i47 = i4;
-      }
-     } else {
-      i46 = i14;
-      i47 = i2;
-     }
-     while (1) {
-      i2 = i46 + 20 | 0;
-      i14 = HEAP32[i2 >> 2] | 0;
-      if (i14) {
-       i46 = i14;
-       i47 = i2;
-       continue;
-      }
-      i2 = i46 + 16 | 0;
-      i14 = HEAP32[i2 >> 2] | 0;
-      if (!i14) {
-       i48 = i46;
-       i49 = i47;
-       break;
-      } else {
-       i46 = i14;
-       i47 = i2;
-      }
-     }
-     if (i49 >>> 0 < i15 >>> 0) _abort(); else {
-      HEAP32[i49 >> 2] = 0;
-      i45 = i48;
-      break;
-     }
-    } else {
-     i2 = HEAP32[i44 + 8 >> 2] | 0;
-     if (i2 >>> 0 < i15 >>> 0) _abort();
-     i14 = i2 + 12 | 0;
-     if ((HEAP32[i14 >> 2] | 0) != (i44 | 0)) _abort();
-     i4 = i7 + 8 | 0;
-     if ((HEAP32[i4 >> 2] | 0) == (i44 | 0)) {
-      HEAP32[i14 >> 2] = i7;
-      HEAP32[i4 >> 2] = i2;
-      i45 = i7;
-      break;
-     } else _abort();
-    } while (0);
-    do if (i3) {
-     i7 = HEAP32[i44 + 28 >> 2] | 0;
-     i15 = 480 + (i7 << 2) | 0;
-     if ((i44 | 0) == (HEAP32[i15 >> 2] | 0)) {
-      HEAP32[i15 >> 2] = i45;
-      if (!i45) {
-       HEAP32[45] = HEAP32[45] & ~(1 << i7);
-       break;
-      }
-     } else {
-      if (i3 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-      i7 = i3 + 16 | 0;
-      if ((HEAP32[i7 >> 2] | 0) == (i44 | 0)) HEAP32[i7 >> 2] = i45; else HEAP32[i3 + 20 >> 2] = i45;
-      if (!i45) break;
-     }
-     i7 = HEAP32[48] | 0;
-     if (i45 >>> 0 < i7 >>> 0) _abort();
-     HEAP32[i45 + 24 >> 2] = i3;
-     i15 = HEAP32[i44 + 16 >> 2] | 0;
-     do if (i15) if (i15 >>> 0 < i7 >>> 0) _abort(); else {
-      HEAP32[i45 + 16 >> 2] = i15;
-      HEAP32[i15 + 24 >> 2] = i45;
-      break;
-     } while (0);
-     i15 = HEAP32[i44 + 20 >> 2] | 0;
-     if (i15) if (i15 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-      HEAP32[i45 + 20 >> 2] = i15;
-      HEAP32[i15 + 24 >> 2] = i45;
-      break;
-     }
-    } while (0);
-    do if (i43 >>> 0 >= 16) {
-     HEAP32[i44 + 4 >> 2] = i5 | 3;
-     HEAP32[i8 + 4 >> 2] = i43 | 1;
-     HEAP32[i8 + i43 >> 2] = i43;
-     i3 = i43 >>> 3;
-     if (i43 >>> 0 < 256) {
-      i15 = 216 + (i3 << 1 << 2) | 0;
-      i7 = HEAP32[44] | 0;
-      i2 = 1 << i3;
-      if (i7 & i2) {
-       i3 = i15 + 8 | 0;
-       i4 = HEAP32[i3 >> 2] | 0;
-       if (i4 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-        i50 = i3;
-        i51 = i4;
-       }
-      } else {
-       HEAP32[44] = i7 | i2;
-       i50 = i15 + 8 | 0;
-       i51 = i15;
-      }
-      HEAP32[i50 >> 2] = i8;
-      HEAP32[i51 + 12 >> 2] = i8;
-      HEAP32[i8 + 8 >> 2] = i51;
-      HEAP32[i8 + 12 >> 2] = i15;
-      break;
-     }
-     i15 = i43 >>> 8;
-     if (i15) if (i43 >>> 0 > 16777215) i52 = 31; else {
-      i2 = (i15 + 1048320 | 0) >>> 16 & 8;
-      i7 = i15 << i2;
-      i15 = (i7 + 520192 | 0) >>> 16 & 4;
-      i4 = i7 << i15;
-      i7 = (i4 + 245760 | 0) >>> 16 & 2;
-      i3 = 14 - (i15 | i2 | i7) + (i4 << i7 >>> 15) | 0;
-      i52 = i43 >>> (i3 + 7 | 0) & 1 | i3 << 1;
-     } else i52 = 0;
-     i3 = 480 + (i52 << 2) | 0;
-     HEAP32[i8 + 28 >> 2] = i52;
-     i7 = i8 + 16 | 0;
-     HEAP32[i7 + 4 >> 2] = 0;
-     HEAP32[i7 >> 2] = 0;
-     i7 = HEAP32[45] | 0;
-     i4 = 1 << i52;
-     if (!(i7 & i4)) {
-      HEAP32[45] = i7 | i4;
-      HEAP32[i3 >> 2] = i8;
-      HEAP32[i8 + 24 >> 2] = i3;
-      HEAP32[i8 + 12 >> 2] = i8;
-      HEAP32[i8 + 8 >> 2] = i8;
-      break;
-     }
-     i4 = i43 << ((i52 | 0) == 31 ? 0 : 25 - (i52 >>> 1) | 0);
-     i7 = HEAP32[i3 >> 2] | 0;
-     while (1) {
-      if ((HEAP32[i7 + 4 >> 2] & -8 | 0) == (i43 | 0)) {
-       i53 = i7;
-       i36 = 148;
-       break;
-      }
-      i3 = i7 + 16 + (i4 >>> 31 << 2) | 0;
-      i2 = HEAP32[i3 >> 2] | 0;
-      if (!i2) {
-       i54 = i3;
-       i55 = i7;
-       i36 = 145;
-       break;
-      } else {
-       i4 = i4 << 1;
-       i7 = i2;
-      }
-     }
-     if ((i36 | 0) == 145) if (i54 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-      HEAP32[i54 >> 2] = i8;
-      HEAP32[i8 + 24 >> 2] = i55;
-      HEAP32[i8 + 12 >> 2] = i8;
-      HEAP32[i8 + 8 >> 2] = i8;
-      break;
-     } else if ((i36 | 0) == 148) {
-      i7 = i53 + 8 | 0;
-      i4 = HEAP32[i7 >> 2] | 0;
-      i2 = HEAP32[48] | 0;
-      if (i4 >>> 0 >= i2 >>> 0 & i53 >>> 0 >= i2 >>> 0) {
-       HEAP32[i4 + 12 >> 2] = i8;
-       HEAP32[i7 >> 2] = i8;
-       HEAP32[i8 + 8 >> 2] = i4;
-       HEAP32[i8 + 12 >> 2] = i53;
-       HEAP32[i8 + 24 >> 2] = 0;
-       break;
-      } else _abort();
-     }
-    } else {
-     i4 = i43 + i5 | 0;
-     HEAP32[i44 + 4 >> 2] = i4 | 3;
-     i7 = i44 + i4 + 4 | 0;
-     HEAP32[i7 >> 2] = HEAP32[i7 >> 2] | 1;
-    } while (0);
-    i13 = i44 + 8 | 0;
-    return i13 | 0;
-   } else i31 = i5;
-  } else i31 = i5;
- } else i31 = -1; while (0);
- i44 = HEAP32[46] | 0;
- if (i44 >>> 0 >= i31 >>> 0) {
-  i43 = i44 - i31 | 0;
-  i53 = HEAP32[49] | 0;
-  if (i43 >>> 0 > 15) {
-   i55 = i53 + i31 | 0;
-   HEAP32[49] = i55;
-   HEAP32[46] = i43;
-   HEAP32[i55 + 4 >> 2] = i43 | 1;
-   HEAP32[i55 + i43 >> 2] = i43;
-   HEAP32[i53 + 4 >> 2] = i31 | 3;
-  } else {
-   HEAP32[46] = 0;
-   HEAP32[49] = 0;
-   HEAP32[i53 + 4 >> 2] = i44 | 3;
-   i43 = i53 + i44 + 4 | 0;
-   HEAP32[i43 >> 2] = HEAP32[i43 >> 2] | 1;
-  }
-  i13 = i53 + 8 | 0;
-  return i13 | 0;
- }
- i53 = HEAP32[47] | 0;
- if (i53 >>> 0 > i31 >>> 0) {
-  i43 = i53 - i31 | 0;
-  HEAP32[47] = i43;
-  i53 = HEAP32[50] | 0;
-  i44 = i53 + i31 | 0;
-  HEAP32[50] = i44;
-  HEAP32[i44 + 4 >> 2] = i43 | 1;
-  HEAP32[i53 + 4 >> 2] = i31 | 3;
-  i13 = i53 + 8 | 0;
-  return i13 | 0;
- }
- do if (!(HEAP32[162] | 0)) {
-  i53 = _sysconf(30) | 0;
-  if (!(i53 + -1 & i53)) {
-   HEAP32[164] = i53;
-   HEAP32[163] = i53;
-   HEAP32[165] = -1;
-   HEAP32[166] = -1;
-   HEAP32[167] = 0;
-   HEAP32[155] = 0;
-   HEAP32[162] = (_time(0) | 0) & -16 ^ 1431655768;
-   break;
-  } else _abort();
- } while (0);
- i53 = i31 + 48 | 0;
- i43 = HEAP32[164] | 0;
- i44 = i31 + 47 | 0;
- i55 = i43 + i44 | 0;
- i54 = 0 - i43 | 0;
- i43 = i55 & i54;
- if (i43 >>> 0 <= i31 >>> 0) {
-  i13 = 0;
-  return i13 | 0;
- }
- i52 = HEAP32[154] | 0;
- if ((i52 | 0) != 0 ? (i51 = HEAP32[152] | 0, i50 = i51 + i43 | 0, i50 >>> 0 <= i51 >>> 0 | i50 >>> 0 > i52 >>> 0) : 0) {
-  i13 = 0;
-  return i13 | 0;
- }
- L257 : do if (!(HEAP32[155] & 4)) {
-  i52 = HEAP32[50] | 0;
-  L259 : do if (i52) {
-   i50 = 624;
-   while (1) {
-    i51 = HEAP32[i50 >> 2] | 0;
-    if (i51 >>> 0 <= i52 >>> 0 ? (i45 = i50 + 4 | 0, (i51 + (HEAP32[i45 >> 2] | 0) | 0) >>> 0 > i52 >>> 0) : 0) {
-     i56 = i50;
-     i57 = i45;
-     break;
-    }
-    i50 = HEAP32[i50 + 8 >> 2] | 0;
-    if (!i50) {
-     i36 = 173;
-     break L259;
-    }
-   }
-   i50 = i55 - (HEAP32[47] | 0) & i54;
-   if (i50 >>> 0 < 2147483647) {
-    i45 = _sbrk(i50 | 0) | 0;
-    if ((i45 | 0) == ((HEAP32[i56 >> 2] | 0) + (HEAP32[i57 >> 2] | 0) | 0)) {
-     if ((i45 | 0) != (-1 | 0)) {
-      i58 = i45;
-      i59 = i50;
-      i36 = 193;
-      break L257;
-     }
-    } else {
-     i60 = i45;
-     i61 = i50;
-     i36 = 183;
-    }
-   }
-  } else i36 = 173; while (0);
-  do if ((i36 | 0) == 173 ? (i52 = _sbrk(0) | 0, (i52 | 0) != (-1 | 0)) : 0) {
-   i5 = i52;
-   i50 = HEAP32[163] | 0;
-   i45 = i50 + -1 | 0;
-   if (!(i45 & i5)) i62 = i43; else i62 = i43 - i5 + (i45 + i5 & 0 - i50) | 0;
-   i50 = HEAP32[152] | 0;
-   i5 = i50 + i62 | 0;
-   if (i62 >>> 0 > i31 >>> 0 & i62 >>> 0 < 2147483647) {
-    i45 = HEAP32[154] | 0;
-    if ((i45 | 0) != 0 ? i5 >>> 0 <= i50 >>> 0 | i5 >>> 0 > i45 >>> 0 : 0) break;
-    i45 = _sbrk(i62 | 0) | 0;
-    if ((i45 | 0) == (i52 | 0)) {
-     i58 = i52;
-     i59 = i62;
-     i36 = 193;
-     break L257;
-    } else {
-     i60 = i45;
-     i61 = i62;
-     i36 = 183;
-    }
-   }
-  } while (0);
-  L279 : do if ((i36 | 0) == 183) {
-   i45 = 0 - i61 | 0;
-   do if (i53 >>> 0 > i61 >>> 0 & (i61 >>> 0 < 2147483647 & (i60 | 0) != (-1 | 0)) ? (i52 = HEAP32[164] | 0, i5 = i44 - i61 + i52 & 0 - i52, i5 >>> 0 < 2147483647) : 0) if ((_sbrk(i5 | 0) | 0) == (-1 | 0)) {
-    _sbrk(i45 | 0) | 0;
-    break L279;
-   } else {
-    i63 = i5 + i61 | 0;
-    break;
-   } else i63 = i61; while (0);
-   if ((i60 | 0) != (-1 | 0)) {
-    i58 = i60;
-    i59 = i63;
-    i36 = 193;
-    break L257;
-   }
-  } while (0);
-  HEAP32[155] = HEAP32[155] | 4;
-  i36 = 190;
- } else i36 = 190; while (0);
- if ((((i36 | 0) == 190 ? i43 >>> 0 < 2147483647 : 0) ? (i63 = _sbrk(i43 | 0) | 0, i43 = _sbrk(0) | 0, i63 >>> 0 < i43 >>> 0 & ((i63 | 0) != (-1 | 0) & (i43 | 0) != (-1 | 0))) : 0) ? (i60 = i43 - i63 | 0, i60 >>> 0 > (i31 + 40 | 0) >>> 0) : 0) {
-  i58 = i63;
-  i59 = i60;
-  i36 = 193;
- }
- if ((i36 | 0) == 193) {
-  i60 = (HEAP32[152] | 0) + i59 | 0;
-  HEAP32[152] = i60;
-  if (i60 >>> 0 > (HEAP32[153] | 0) >>> 0) HEAP32[153] = i60;
-  i60 = HEAP32[50] | 0;
-  do if (i60) {
-   i63 = 624;
-   do {
-    i43 = HEAP32[i63 >> 2] | 0;
-    i61 = i63 + 4 | 0;
-    i44 = HEAP32[i61 >> 2] | 0;
-    if ((i58 | 0) == (i43 + i44 | 0)) {
-     i64 = i43;
-     i65 = i61;
-     i66 = i44;
-     i67 = i63;
-     i36 = 203;
-     break;
-    }
-    i63 = HEAP32[i63 + 8 >> 2] | 0;
-   } while ((i63 | 0) != 0);
-   if (((i36 | 0) == 203 ? (HEAP32[i67 + 12 >> 2] & 8 | 0) == 0 : 0) ? i60 >>> 0 < i58 >>> 0 & i60 >>> 0 >= i64 >>> 0 : 0) {
-    HEAP32[i65 >> 2] = i66 + i59;
-    i63 = i60 + 8 | 0;
-    i44 = (i63 & 7 | 0) == 0 ? 0 : 0 - i63 & 7;
-    i63 = i60 + i44 | 0;
-    i61 = i59 - i44 + (HEAP32[47] | 0) | 0;
-    HEAP32[50] = i63;
-    HEAP32[47] = i61;
-    HEAP32[i63 + 4 >> 2] = i61 | 1;
-    HEAP32[i63 + i61 + 4 >> 2] = 40;
-    HEAP32[51] = HEAP32[166];
-    break;
-   }
-   i61 = HEAP32[48] | 0;
-   if (i58 >>> 0 < i61 >>> 0) {
-    HEAP32[48] = i58;
-    i68 = i58;
-   } else i68 = i61;
-   i61 = i58 + i59 | 0;
-   i63 = 624;
-   while (1) {
-    if ((HEAP32[i63 >> 2] | 0) == (i61 | 0)) {
-     i69 = i63;
-     i70 = i63;
-     i36 = 211;
-     break;
-    }
-    i63 = HEAP32[i63 + 8 >> 2] | 0;
-    if (!i63) {
-     i71 = 624;
-     break;
-    }
-   }
-   if ((i36 | 0) == 211) if (!(HEAP32[i70 + 12 >> 2] & 8)) {
-    HEAP32[i69 >> 2] = i58;
-    i63 = i70 + 4 | 0;
-    HEAP32[i63 >> 2] = (HEAP32[i63 >> 2] | 0) + i59;
-    i63 = i58 + 8 | 0;
-    i44 = i58 + ((i63 & 7 | 0) == 0 ? 0 : 0 - i63 & 7) | 0;
-    i63 = i61 + 8 | 0;
-    i43 = i61 + ((i63 & 7 | 0) == 0 ? 0 : 0 - i63 & 7) | 0;
-    i63 = i44 + i31 | 0;
-    i53 = i43 - i44 - i31 | 0;
-    HEAP32[i44 + 4 >> 2] = i31 | 3;
-    do if ((i43 | 0) != (i60 | 0)) {
-     if ((i43 | 0) == (HEAP32[49] | 0)) {
-      i62 = (HEAP32[46] | 0) + i53 | 0;
-      HEAP32[46] = i62;
-      HEAP32[49] = i63;
-      HEAP32[i63 + 4 >> 2] = i62 | 1;
-      HEAP32[i63 + i62 >> 2] = i62;
-      break;
-     }
-     i62 = HEAP32[i43 + 4 >> 2] | 0;
-     if ((i62 & 3 | 0) == 1) {
-      i57 = i62 & -8;
-      i56 = i62 >>> 3;
-      L331 : do if (i62 >>> 0 >= 256) {
-       i54 = HEAP32[i43 + 24 >> 2] | 0;
-       i55 = HEAP32[i43 + 12 >> 2] | 0;
-       do if ((i55 | 0) == (i43 | 0)) {
-        i45 = i43 + 16 | 0;
-        i5 = i45 + 4 | 0;
-        i52 = HEAP32[i5 >> 2] | 0;
-        if (!i52) {
-         i50 = HEAP32[i45 >> 2] | 0;
-         if (!i50) {
-          i72 = 0;
-          break;
-         } else {
-          i73 = i50;
-          i74 = i45;
-         }
-        } else {
-         i73 = i52;
-         i74 = i5;
-        }
-        while (1) {
-         i5 = i73 + 20 | 0;
-         i52 = HEAP32[i5 >> 2] | 0;
-         if (i52) {
-          i73 = i52;
-          i74 = i5;
-          continue;
-         }
-         i5 = i73 + 16 | 0;
-         i52 = HEAP32[i5 >> 2] | 0;
-         if (!i52) {
-          i75 = i73;
-          i76 = i74;
-          break;
-         } else {
-          i73 = i52;
-          i74 = i5;
-         }
-        }
-        if (i76 >>> 0 < i68 >>> 0) _abort(); else {
-         HEAP32[i76 >> 2] = 0;
-         i72 = i75;
-         break;
-        }
-       } else {
-        i5 = HEAP32[i43 + 8 >> 2] | 0;
-        if (i5 >>> 0 < i68 >>> 0) _abort();
-        i52 = i5 + 12 | 0;
-        if ((HEAP32[i52 >> 2] | 0) != (i43 | 0)) _abort();
-        i45 = i55 + 8 | 0;
-        if ((HEAP32[i45 >> 2] | 0) == (i43 | 0)) {
-         HEAP32[i52 >> 2] = i55;
-         HEAP32[i45 >> 2] = i5;
-         i72 = i55;
-         break;
-        } else _abort();
-       } while (0);
-       if (!i54) break;
-       i55 = HEAP32[i43 + 28 >> 2] | 0;
-       i5 = 480 + (i55 << 2) | 0;
-       do if ((i43 | 0) != (HEAP32[i5 >> 2] | 0)) {
-        if (i54 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-        i45 = i54 + 16 | 0;
-        if ((HEAP32[i45 >> 2] | 0) == (i43 | 0)) HEAP32[i45 >> 2] = i72; else HEAP32[i54 + 20 >> 2] = i72;
-        if (!i72) break L331;
-       } else {
-        HEAP32[i5 >> 2] = i72;
-        if (i72) break;
-        HEAP32[45] = HEAP32[45] & ~(1 << i55);
-        break L331;
-       } while (0);
-       i55 = HEAP32[48] | 0;
-       if (i72 >>> 0 < i55 >>> 0) _abort();
-       HEAP32[i72 + 24 >> 2] = i54;
-       i5 = i43 + 16 | 0;
-       i45 = HEAP32[i5 >> 2] | 0;
-       do if (i45) if (i45 >>> 0 < i55 >>> 0) _abort(); else {
-        HEAP32[i72 + 16 >> 2] = i45;
-        HEAP32[i45 + 24 >> 2] = i72;
-        break;
-       } while (0);
-       i45 = HEAP32[i5 + 4 >> 2] | 0;
-       if (!i45) break;
-       if (i45 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-        HEAP32[i72 + 20 >> 2] = i45;
-        HEAP32[i45 + 24 >> 2] = i72;
-        break;
-       }
-      } else {
-       i45 = HEAP32[i43 + 8 >> 2] | 0;
-       i55 = HEAP32[i43 + 12 >> 2] | 0;
-       i54 = 216 + (i56 << 1 << 2) | 0;
-       do if ((i45 | 0) != (i54 | 0)) {
-        if (i45 >>> 0 < i68 >>> 0) _abort();
-        if ((HEAP32[i45 + 12 >> 2] | 0) == (i43 | 0)) break;
-        _abort();
-       } while (0);
-       if ((i55 | 0) == (i45 | 0)) {
-        HEAP32[44] = HEAP32[44] & ~(1 << i56);
-        break;
-       }
-       do if ((i55 | 0) == (i54 | 0)) i77 = i55 + 8 | 0; else {
-        if (i55 >>> 0 < i68 >>> 0) _abort();
-        i5 = i55 + 8 | 0;
-        if ((HEAP32[i5 >> 2] | 0) == (i43 | 0)) {
-         i77 = i5;
-         break;
-        }
-        _abort();
-       } while (0);
-       HEAP32[i45 + 12 >> 2] = i55;
-       HEAP32[i77 >> 2] = i45;
-      } while (0);
-      i78 = i43 + i57 | 0;
-      i79 = i57 + i53 | 0;
-     } else {
-      i78 = i43;
-      i79 = i53;
-     }
-     i56 = i78 + 4 | 0;
-     HEAP32[i56 >> 2] = HEAP32[i56 >> 2] & -2;
-     HEAP32[i63 + 4 >> 2] = i79 | 1;
-     HEAP32[i63 + i79 >> 2] = i79;
-     i56 = i79 >>> 3;
-     if (i79 >>> 0 < 256) {
-      i62 = 216 + (i56 << 1 << 2) | 0;
-      i54 = HEAP32[44] | 0;
-      i5 = 1 << i56;
-      do if (!(i54 & i5)) {
-       HEAP32[44] = i54 | i5;
-       i80 = i62 + 8 | 0;
-       i81 = i62;
-      } else {
-       i56 = i62 + 8 | 0;
-       i52 = HEAP32[i56 >> 2] | 0;
-       if (i52 >>> 0 >= (HEAP32[48] | 0) >>> 0) {
-        i80 = i56;
-        i81 = i52;
-        break;
-       }
-       _abort();
-      } while (0);
-      HEAP32[i80 >> 2] = i63;
-      HEAP32[i81 + 12 >> 2] = i63;
-      HEAP32[i63 + 8 >> 2] = i81;
-      HEAP32[i63 + 12 >> 2] = i62;
-      break;
-     }
-     i5 = i79 >>> 8;
-     do if (!i5) i82 = 0; else {
-      if (i79 >>> 0 > 16777215) {
-       i82 = 31;
-       break;
-      }
-      i54 = (i5 + 1048320 | 0) >>> 16 & 8;
-      i57 = i5 << i54;
-      i52 = (i57 + 520192 | 0) >>> 16 & 4;
-      i56 = i57 << i52;
-      i57 = (i56 + 245760 | 0) >>> 16 & 2;
-      i50 = 14 - (i52 | i54 | i57) + (i56 << i57 >>> 15) | 0;
-      i82 = i79 >>> (i50 + 7 | 0) & 1 | i50 << 1;
-     } while (0);
-     i5 = 480 + (i82 << 2) | 0;
-     HEAP32[i63 + 28 >> 2] = i82;
-     i62 = i63 + 16 | 0;
-     HEAP32[i62 + 4 >> 2] = 0;
-     HEAP32[i62 >> 2] = 0;
-     i62 = HEAP32[45] | 0;
-     i50 = 1 << i82;
-     if (!(i62 & i50)) {
-      HEAP32[45] = i62 | i50;
-      HEAP32[i5 >> 2] = i63;
-      HEAP32[i63 + 24 >> 2] = i5;
-      HEAP32[i63 + 12 >> 2] = i63;
-      HEAP32[i63 + 8 >> 2] = i63;
-      break;
-     }
-     i50 = i79 << ((i82 | 0) == 31 ? 0 : 25 - (i82 >>> 1) | 0);
-     i62 = HEAP32[i5 >> 2] | 0;
-     while (1) {
-      if ((HEAP32[i62 + 4 >> 2] & -8 | 0) == (i79 | 0)) {
-       i83 = i62;
-       i36 = 281;
-       break;
-      }
-      i5 = i62 + 16 + (i50 >>> 31 << 2) | 0;
-      i57 = HEAP32[i5 >> 2] | 0;
-      if (!i57) {
-       i84 = i5;
-       i85 = i62;
-       i36 = 278;
-       break;
-      } else {
-       i50 = i50 << 1;
-       i62 = i57;
-      }
-     }
-     if ((i36 | 0) == 278) if (i84 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-      HEAP32[i84 >> 2] = i63;
-      HEAP32[i63 + 24 >> 2] = i85;
-      HEAP32[i63 + 12 >> 2] = i63;
-      HEAP32[i63 + 8 >> 2] = i63;
-      break;
-     } else if ((i36 | 0) == 281) {
-      i62 = i83 + 8 | 0;
-      i50 = HEAP32[i62 >> 2] | 0;
-      i57 = HEAP32[48] | 0;
-      if (i50 >>> 0 >= i57 >>> 0 & i83 >>> 0 >= i57 >>> 0) {
-       HEAP32[i50 + 12 >> 2] = i63;
-       HEAP32[i62 >> 2] = i63;
-       HEAP32[i63 + 8 >> 2] = i50;
-       HEAP32[i63 + 12 >> 2] = i83;
-       HEAP32[i63 + 24 >> 2] = 0;
-       break;
-      } else _abort();
-     }
-    } else {
-     i50 = (HEAP32[47] | 0) + i53 | 0;
-     HEAP32[47] = i50;
-     HEAP32[50] = i63;
-     HEAP32[i63 + 4 >> 2] = i50 | 1;
-    } while (0);
-    i13 = i44 + 8 | 0;
-    return i13 | 0;
-   } else i71 = 624;
-   while (1) {
-    i63 = HEAP32[i71 >> 2] | 0;
-    if (i63 >>> 0 <= i60 >>> 0 ? (i53 = i63 + (HEAP32[i71 + 4 >> 2] | 0) | 0, i53 >>> 0 > i60 >>> 0) : 0) {
-     i86 = i53;
-     break;
-    }
-    i71 = HEAP32[i71 + 8 >> 2] | 0;
-   }
-   i44 = i86 + -47 | 0;
-   i53 = i44 + 8 | 0;
-   i63 = i44 + ((i53 & 7 | 0) == 0 ? 0 : 0 - i53 & 7) | 0;
-   i53 = i60 + 16 | 0;
-   i44 = i63 >>> 0 < i53 >>> 0 ? i60 : i63;
-   i63 = i44 + 8 | 0;
-   i43 = i58 + 8 | 0;
-   i61 = (i43 & 7 | 0) == 0 ? 0 : 0 - i43 & 7;
-   i43 = i58 + i61 | 0;
-   i50 = i59 + -40 - i61 | 0;
-   HEAP32[50] = i43;
-   HEAP32[47] = i50;
-   HEAP32[i43 + 4 >> 2] = i50 | 1;
-   HEAP32[i43 + i50 + 4 >> 2] = 40;
-   HEAP32[51] = HEAP32[166];
-   i50 = i44 + 4 | 0;
-   HEAP32[i50 >> 2] = 27;
-   HEAP32[i63 >> 2] = HEAP32[156];
-   HEAP32[i63 + 4 >> 2] = HEAP32[157];
-   HEAP32[i63 + 8 >> 2] = HEAP32[158];
-   HEAP32[i63 + 12 >> 2] = HEAP32[159];
-   HEAP32[156] = i58;
-   HEAP32[157] = i59;
-   HEAP32[159] = 0;
-   HEAP32[158] = i63;
-   i63 = i44 + 24 | 0;
-   do {
-    i63 = i63 + 4 | 0;
-    HEAP32[i63 >> 2] = 7;
-   } while ((i63 + 4 | 0) >>> 0 < i86 >>> 0);
-   if ((i44 | 0) != (i60 | 0)) {
-    i63 = i44 - i60 | 0;
-    HEAP32[i50 >> 2] = HEAP32[i50 >> 2] & -2;
-    HEAP32[i60 + 4 >> 2] = i63 | 1;
-    HEAP32[i44 >> 2] = i63;
-    i43 = i63 >>> 3;
-    if (i63 >>> 0 < 256) {
-     i61 = 216 + (i43 << 1 << 2) | 0;
-     i62 = HEAP32[44] | 0;
-     i57 = 1 << i43;
-     if (i62 & i57) {
-      i43 = i61 + 8 | 0;
-      i5 = HEAP32[i43 >> 2] | 0;
-      if (i5 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-       i87 = i43;
-       i88 = i5;
-      }
-     } else {
-      HEAP32[44] = i62 | i57;
-      i87 = i61 + 8 | 0;
-      i88 = i61;
-     }
-     HEAP32[i87 >> 2] = i60;
-     HEAP32[i88 + 12 >> 2] = i60;
-     HEAP32[i60 + 8 >> 2] = i88;
-     HEAP32[i60 + 12 >> 2] = i61;
-     break;
-    }
-    i61 = i63 >>> 8;
-    if (i61) if (i63 >>> 0 > 16777215) i89 = 31; else {
-     i57 = (i61 + 1048320 | 0) >>> 16 & 8;
-     i62 = i61 << i57;
-     i61 = (i62 + 520192 | 0) >>> 16 & 4;
-     i5 = i62 << i61;
-     i62 = (i5 + 245760 | 0) >>> 16 & 2;
-     i43 = 14 - (i61 | i57 | i62) + (i5 << i62 >>> 15) | 0;
-     i89 = i63 >>> (i43 + 7 | 0) & 1 | i43 << 1;
-    } else i89 = 0;
-    i43 = 480 + (i89 << 2) | 0;
-    HEAP32[i60 + 28 >> 2] = i89;
-    HEAP32[i60 + 20 >> 2] = 0;
-    HEAP32[i53 >> 2] = 0;
-    i62 = HEAP32[45] | 0;
-    i5 = 1 << i89;
-    if (!(i62 & i5)) {
-     HEAP32[45] = i62 | i5;
-     HEAP32[i43 >> 2] = i60;
-     HEAP32[i60 + 24 >> 2] = i43;
-     HEAP32[i60 + 12 >> 2] = i60;
-     HEAP32[i60 + 8 >> 2] = i60;
-     break;
-    }
-    i5 = i63 << ((i89 | 0) == 31 ? 0 : 25 - (i89 >>> 1) | 0);
-    i62 = HEAP32[i43 >> 2] | 0;
-    while (1) {
-     if ((HEAP32[i62 + 4 >> 2] & -8 | 0) == (i63 | 0)) {
-      i90 = i62;
-      i36 = 307;
-      break;
-     }
-     i43 = i62 + 16 + (i5 >>> 31 << 2) | 0;
-     i57 = HEAP32[i43 >> 2] | 0;
-     if (!i57) {
-      i91 = i43;
-      i92 = i62;
-      i36 = 304;
-      break;
-     } else {
-      i5 = i5 << 1;
-      i62 = i57;
-     }
-    }
-    if ((i36 | 0) == 304) if (i91 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-     HEAP32[i91 >> 2] = i60;
-     HEAP32[i60 + 24 >> 2] = i92;
-     HEAP32[i60 + 12 >> 2] = i60;
-     HEAP32[i60 + 8 >> 2] = i60;
-     break;
-    } else if ((i36 | 0) == 307) {
-     i62 = i90 + 8 | 0;
-     i5 = HEAP32[i62 >> 2] | 0;
-     i63 = HEAP32[48] | 0;
-     if (i5 >>> 0 >= i63 >>> 0 & i90 >>> 0 >= i63 >>> 0) {
-      HEAP32[i5 + 12 >> 2] = i60;
-      HEAP32[i62 >> 2] = i60;
-      HEAP32[i60 + 8 >> 2] = i5;
-      HEAP32[i60 + 12 >> 2] = i90;
-      HEAP32[i60 + 24 >> 2] = 0;
-      break;
-     } else _abort();
-    }
-   }
-  } else {
-   i5 = HEAP32[48] | 0;
-   if ((i5 | 0) == 0 | i58 >>> 0 < i5 >>> 0) HEAP32[48] = i58;
-   HEAP32[156] = i58;
-   HEAP32[157] = i59;
-   HEAP32[159] = 0;
-   HEAP32[53] = HEAP32[162];
-   HEAP32[52] = -1;
-   i5 = 0;
-   do {
-    i62 = 216 + (i5 << 1 << 2) | 0;
-    HEAP32[i62 + 12 >> 2] = i62;
-    HEAP32[i62 + 8 >> 2] = i62;
-    i5 = i5 + 1 | 0;
-   } while ((i5 | 0) != 32);
-   i5 = i58 + 8 | 0;
-   i62 = (i5 & 7 | 0) == 0 ? 0 : 0 - i5 & 7;
-   i5 = i58 + i62 | 0;
-   i63 = i59 + -40 - i62 | 0;
-   HEAP32[50] = i5;
-   HEAP32[47] = i63;
-   HEAP32[i5 + 4 >> 2] = i63 | 1;
-   HEAP32[i5 + i63 + 4 >> 2] = 40;
-   HEAP32[51] = HEAP32[166];
-  } while (0);
-  i59 = HEAP32[47] | 0;
-  if (i59 >>> 0 > i31 >>> 0) {
-   i58 = i59 - i31 | 0;
-   HEAP32[47] = i58;
-   i59 = HEAP32[50] | 0;
-   i60 = i59 + i31 | 0;
-   HEAP32[50] = i60;
-   HEAP32[i60 + 4 >> 2] = i58 | 1;
-   HEAP32[i59 + 4 >> 2] = i31 | 3;
-   i13 = i59 + 8 | 0;
-   return i13 | 0;
-  }
- }
- HEAP32[(___errno_location() | 0) >> 2] = 12;
- i13 = 0;
- return i13 | 0;
-}
-
-function _free(i1) {
- i1 = i1 | 0;
- var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0, i25 = 0, i26 = 0, i27 = 0, i28 = 0, i29 = 0, i30 = 0, i31 = 0, i32 = 0, i33 = 0, i34 = 0, i35 = 0, i36 = 0, i37 = 0;
- if (!i1) return;
- i2 = i1 + -8 | 0;
- i3 = HEAP32[48] | 0;
- if (i2 >>> 0 < i3 >>> 0) _abort();
- i4 = HEAP32[i1 + -4 >> 2] | 0;
- i1 = i4 & 3;
- if ((i1 | 0) == 1) _abort();
- i5 = i4 & -8;
- i6 = i2 + i5 | 0;
- do if (!(i4 & 1)) {
-  i7 = HEAP32[i2 >> 2] | 0;
-  if (!i1) return;
-  i8 = i2 + (0 - i7) | 0;
-  i9 = i7 + i5 | 0;
-  if (i8 >>> 0 < i3 >>> 0) _abort();
-  if ((i8 | 0) == (HEAP32[49] | 0)) {
-   i10 = i6 + 4 | 0;
-   i11 = HEAP32[i10 >> 2] | 0;
-   if ((i11 & 3 | 0) != 3) {
-    i12 = i8;
-    i13 = i9;
-    break;
-   }
-   HEAP32[46] = i9;
-   HEAP32[i10 >> 2] = i11 & -2;
-   HEAP32[i8 + 4 >> 2] = i9 | 1;
-   HEAP32[i8 + i9 >> 2] = i9;
-   return;
-  }
-  i11 = i7 >>> 3;
-  if (i7 >>> 0 < 256) {
-   i7 = HEAP32[i8 + 8 >> 2] | 0;
-   i10 = HEAP32[i8 + 12 >> 2] | 0;
-   i14 = 216 + (i11 << 1 << 2) | 0;
-   if ((i7 | 0) != (i14 | 0)) {
-    if (i7 >>> 0 < i3 >>> 0) _abort();
-    if ((HEAP32[i7 + 12 >> 2] | 0) != (i8 | 0)) _abort();
-   }
-   if ((i10 | 0) == (i7 | 0)) {
-    HEAP32[44] = HEAP32[44] & ~(1 << i11);
-    i12 = i8;
-    i13 = i9;
-    break;
-   }
-   if ((i10 | 0) != (i14 | 0)) {
-    if (i10 >>> 0 < i3 >>> 0) _abort();
-    i14 = i10 + 8 | 0;
-    if ((HEAP32[i14 >> 2] | 0) == (i8 | 0)) i15 = i14; else _abort();
-   } else i15 = i10 + 8 | 0;
-   HEAP32[i7 + 12 >> 2] = i10;
-   HEAP32[i15 >> 2] = i7;
-   i12 = i8;
-   i13 = i9;
-   break;
-  }
-  i7 = HEAP32[i8 + 24 >> 2] | 0;
-  i10 = HEAP32[i8 + 12 >> 2] | 0;
-  do if ((i10 | 0) == (i8 | 0)) {
-   i14 = i8 + 16 | 0;
-   i11 = i14 + 4 | 0;
-   i16 = HEAP32[i11 >> 2] | 0;
-   if (!i16) {
-    i17 = HEAP32[i14 >> 2] | 0;
-    if (!i17) {
-     i18 = 0;
-     break;
-    } else {
-     i19 = i17;
-     i20 = i14;
-    }
-   } else {
-    i19 = i16;
-    i20 = i11;
-   }
-   while (1) {
-    i11 = i19 + 20 | 0;
-    i16 = HEAP32[i11 >> 2] | 0;
-    if (i16) {
-     i19 = i16;
-     i20 = i11;
-     continue;
-    }
-    i11 = i19 + 16 | 0;
-    i16 = HEAP32[i11 >> 2] | 0;
-    if (!i16) {
-     i21 = i19;
-     i22 = i20;
-     break;
-    } else {
-     i19 = i16;
-     i20 = i11;
-    }
-   }
-   if (i22 >>> 0 < i3 >>> 0) _abort(); else {
-    HEAP32[i22 >> 2] = 0;
-    i18 = i21;
-    break;
-   }
-  } else {
-   i11 = HEAP32[i8 + 8 >> 2] | 0;
-   if (i11 >>> 0 < i3 >>> 0) _abort();
-   i16 = i11 + 12 | 0;
-   if ((HEAP32[i16 >> 2] | 0) != (i8 | 0)) _abort();
-   i14 = i10 + 8 | 0;
-   if ((HEAP32[i14 >> 2] | 0) == (i8 | 0)) {
-    HEAP32[i16 >> 2] = i10;
-    HEAP32[i14 >> 2] = i11;
-    i18 = i10;
-    break;
-   } else _abort();
-  } while (0);
-  if (i7) {
-   i10 = HEAP32[i8 + 28 >> 2] | 0;
-   i11 = 480 + (i10 << 2) | 0;
-   if ((i8 | 0) == (HEAP32[i11 >> 2] | 0)) {
-    HEAP32[i11 >> 2] = i18;
-    if (!i18) {
-     HEAP32[45] = HEAP32[45] & ~(1 << i10);
-     i12 = i8;
-     i13 = i9;
-     break;
-    }
-   } else {
-    if (i7 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-    i10 = i7 + 16 | 0;
-    if ((HEAP32[i10 >> 2] | 0) == (i8 | 0)) HEAP32[i10 >> 2] = i18; else HEAP32[i7 + 20 >> 2] = i18;
-    if (!i18) {
-     i12 = i8;
-     i13 = i9;
-     break;
-    }
-   }
-   i10 = HEAP32[48] | 0;
-   if (i18 >>> 0 < i10 >>> 0) _abort();
-   HEAP32[i18 + 24 >> 2] = i7;
-   i11 = i8 + 16 | 0;
-   i14 = HEAP32[i11 >> 2] | 0;
-   do if (i14) if (i14 >>> 0 < i10 >>> 0) _abort(); else {
-    HEAP32[i18 + 16 >> 2] = i14;
-    HEAP32[i14 + 24 >> 2] = i18;
-    break;
-   } while (0);
-   i14 = HEAP32[i11 + 4 >> 2] | 0;
-   if (i14) if (i14 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-    HEAP32[i18 + 20 >> 2] = i14;
-    HEAP32[i14 + 24 >> 2] = i18;
-    i12 = i8;
-    i13 = i9;
-    break;
-   } else {
-    i12 = i8;
-    i13 = i9;
-   }
-  } else {
-   i12 = i8;
-   i13 = i9;
-  }
- } else {
-  i12 = i2;
-  i13 = i5;
- } while (0);
- if (i12 >>> 0 >= i6 >>> 0) _abort();
- i5 = i6 + 4 | 0;
- i2 = HEAP32[i5 >> 2] | 0;
- if (!(i2 & 1)) _abort();
- if (!(i2 & 2)) {
-  if ((i6 | 0) == (HEAP32[50] | 0)) {
-   i18 = (HEAP32[47] | 0) + i13 | 0;
-   HEAP32[47] = i18;
-   HEAP32[50] = i12;
-   HEAP32[i12 + 4 >> 2] = i18 | 1;
-   if ((i12 | 0) != (HEAP32[49] | 0)) return;
-   HEAP32[49] = 0;
-   HEAP32[46] = 0;
-   return;
-  }
-  if ((i6 | 0) == (HEAP32[49] | 0)) {
-   i18 = (HEAP32[46] | 0) + i13 | 0;
-   HEAP32[46] = i18;
-   HEAP32[49] = i12;
-   HEAP32[i12 + 4 >> 2] = i18 | 1;
-   HEAP32[i12 + i18 >> 2] = i18;
-   return;
-  }
-  i18 = (i2 & -8) + i13 | 0;
-  i3 = i2 >>> 3;
-  do if (i2 >>> 0 >= 256) {
-   i21 = HEAP32[i6 + 24 >> 2] | 0;
-   i22 = HEAP32[i6 + 12 >> 2] | 0;
-   do if ((i22 | 0) == (i6 | 0)) {
-    i20 = i6 + 16 | 0;
-    i19 = i20 + 4 | 0;
-    i15 = HEAP32[i19 >> 2] | 0;
-    if (!i15) {
-     i1 = HEAP32[i20 >> 2] | 0;
-     if (!i1) {
-      i23 = 0;
-      break;
-     } else {
-      i24 = i1;
-      i25 = i20;
-     }
-    } else {
-     i24 = i15;
-     i25 = i19;
-    }
-    while (1) {
-     i19 = i24 + 20 | 0;
-     i15 = HEAP32[i19 >> 2] | 0;
-     if (i15) {
-      i24 = i15;
-      i25 = i19;
-      continue;
-     }
-     i19 = i24 + 16 | 0;
-     i15 = HEAP32[i19 >> 2] | 0;
-     if (!i15) {
-      i26 = i24;
-      i27 = i25;
-      break;
-     } else {
-      i24 = i15;
-      i25 = i19;
-     }
-    }
-    if (i27 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-     HEAP32[i27 >> 2] = 0;
-     i23 = i26;
-     break;
-    }
-   } else {
-    i19 = HEAP32[i6 + 8 >> 2] | 0;
-    if (i19 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-    i15 = i19 + 12 | 0;
-    if ((HEAP32[i15 >> 2] | 0) != (i6 | 0)) _abort();
-    i20 = i22 + 8 | 0;
-    if ((HEAP32[i20 >> 2] | 0) == (i6 | 0)) {
-     HEAP32[i15 >> 2] = i22;
-     HEAP32[i20 >> 2] = i19;
-     i23 = i22;
-     break;
-    } else _abort();
-   } while (0);
-   if (i21) {
-    i22 = HEAP32[i6 + 28 >> 2] | 0;
-    i9 = 480 + (i22 << 2) | 0;
-    if ((i6 | 0) == (HEAP32[i9 >> 2] | 0)) {
-     HEAP32[i9 >> 2] = i23;
-     if (!i23) {
-      HEAP32[45] = HEAP32[45] & ~(1 << i22);
-      break;
-     }
-    } else {
-     if (i21 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-     i22 = i21 + 16 | 0;
-     if ((HEAP32[i22 >> 2] | 0) == (i6 | 0)) HEAP32[i22 >> 2] = i23; else HEAP32[i21 + 20 >> 2] = i23;
-     if (!i23) break;
-    }
-    i22 = HEAP32[48] | 0;
-    if (i23 >>> 0 < i22 >>> 0) _abort();
-    HEAP32[i23 + 24 >> 2] = i21;
-    i9 = i6 + 16 | 0;
-    i8 = HEAP32[i9 >> 2] | 0;
-    do if (i8) if (i8 >>> 0 < i22 >>> 0) _abort(); else {
-     HEAP32[i23 + 16 >> 2] = i8;
-     HEAP32[i8 + 24 >> 2] = i23;
-     break;
-    } while (0);
-    i8 = HEAP32[i9 + 4 >> 2] | 0;
-    if (i8) if (i8 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-     HEAP32[i23 + 20 >> 2] = i8;
-     HEAP32[i8 + 24 >> 2] = i23;
-     break;
-    }
-   }
-  } else {
-   i8 = HEAP32[i6 + 8 >> 2] | 0;
-   i22 = HEAP32[i6 + 12 >> 2] | 0;
-   i21 = 216 + (i3 << 1 << 2) | 0;
-   if ((i8 | 0) != (i21 | 0)) {
-    if (i8 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-    if ((HEAP32[i8 + 12 >> 2] | 0) != (i6 | 0)) _abort();
-   }
-   if ((i22 | 0) == (i8 | 0)) {
-    HEAP32[44] = HEAP32[44] & ~(1 << i3);
-    break;
-   }
-   if ((i22 | 0) != (i21 | 0)) {
-    if (i22 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort();
-    i21 = i22 + 8 | 0;
-    if ((HEAP32[i21 >> 2] | 0) == (i6 | 0)) i28 = i21; else _abort();
-   } else i28 = i22 + 8 | 0;
-   HEAP32[i8 + 12 >> 2] = i22;
-   HEAP32[i28 >> 2] = i8;
-  } while (0);
-  HEAP32[i12 + 4 >> 2] = i18 | 1;
-  HEAP32[i12 + i18 >> 2] = i18;
-  if ((i12 | 0) == (HEAP32[49] | 0)) {
-   HEAP32[46] = i18;
-   return;
-  } else i29 = i18;
- } else {
-  HEAP32[i5 >> 2] = i2 & -2;
-  HEAP32[i12 + 4 >> 2] = i13 | 1;
-  HEAP32[i12 + i13 >> 2] = i13;
-  i29 = i13;
- }
- i13 = i29 >>> 3;
- if (i29 >>> 0 < 256) {
-  i2 = 216 + (i13 << 1 << 2) | 0;
-  i5 = HEAP32[44] | 0;
-  i18 = 1 << i13;
-  if (i5 & i18) {
-   i13 = i2 + 8 | 0;
-   i28 = HEAP32[i13 >> 2] | 0;
-   if (i28 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-    i30 = i13;
-    i31 = i28;
-   }
-  } else {
-   HEAP32[44] = i5 | i18;
-   i30 = i2 + 8 | 0;
-   i31 = i2;
-  }
-  HEAP32[i30 >> 2] = i12;
-  HEAP32[i31 + 12 >> 2] = i12;
-  HEAP32[i12 + 8 >> 2] = i31;
-  HEAP32[i12 + 12 >> 2] = i2;
-  return;
- }
- i2 = i29 >>> 8;
- if (i2) if (i29 >>> 0 > 16777215) i32 = 31; else {
-  i31 = (i2 + 1048320 | 0) >>> 16 & 8;
-  i30 = i2 << i31;
-  i2 = (i30 + 520192 | 0) >>> 16 & 4;
-  i18 = i30 << i2;
-  i30 = (i18 + 245760 | 0) >>> 16 & 2;
-  i5 = 14 - (i2 | i31 | i30) + (i18 << i30 >>> 15) | 0;
-  i32 = i29 >>> (i5 + 7 | 0) & 1 | i5 << 1;
- } else i32 = 0;
- i5 = 480 + (i32 << 2) | 0;
- HEAP32[i12 + 28 >> 2] = i32;
- HEAP32[i12 + 20 >> 2] = 0;
- HEAP32[i12 + 16 >> 2] = 0;
- i30 = HEAP32[45] | 0;
- i18 = 1 << i32;
- do if (i30 & i18) {
-  i31 = i29 << ((i32 | 0) == 31 ? 0 : 25 - (i32 >>> 1) | 0);
-  i2 = HEAP32[i5 >> 2] | 0;
-  while (1) {
-   if ((HEAP32[i2 + 4 >> 2] & -8 | 0) == (i29 | 0)) {
-    i33 = i2;
-    i34 = 130;
-    break;
-   }
-   i28 = i2 + 16 + (i31 >>> 31 << 2) | 0;
-   i13 = HEAP32[i28 >> 2] | 0;
-   if (!i13) {
-    i35 = i28;
-    i36 = i2;
-    i34 = 127;
-    break;
-   } else {
-    i31 = i31 << 1;
-    i2 = i13;
-   }
-  }
-  if ((i34 | 0) == 127) if (i35 >>> 0 < (HEAP32[48] | 0) >>> 0) _abort(); else {
-   HEAP32[i35 >> 2] = i12;
-   HEAP32[i12 + 24 >> 2] = i36;
-   HEAP32[i12 + 12 >> 2] = i12;
-   HEAP32[i12 + 8 >> 2] = i12;
-   break;
-  } else if ((i34 | 0) == 130) {
-   i2 = i33 + 8 | 0;
-   i31 = HEAP32[i2 >> 2] | 0;
-   i9 = HEAP32[48] | 0;
-   if (i31 >>> 0 >= i9 >>> 0 & i33 >>> 0 >= i9 >>> 0) {
-    HEAP32[i31 + 12 >> 2] = i12;
-    HEAP32[i2 >> 2] = i12;
-    HEAP32[i12 + 8 >> 2] = i31;
-    HEAP32[i12 + 12 >> 2] = i33;
-    HEAP32[i12 + 24 >> 2] = 0;
-    break;
-   } else _abort();
-  }
- } else {
-  HEAP32[45] = i30 | i18;
-  HEAP32[i5 >> 2] = i12;
-  HEAP32[i12 + 24 >> 2] = i5;
-  HEAP32[i12 + 12 >> 2] = i12;
-  HEAP32[i12 + 8 >> 2] = i12;
- } while (0);
- i12 = (HEAP32[52] | 0) + -1 | 0;
- HEAP32[52] = i12;
- if (!i12) i37 = 632; else return;
- while (1) {
-  i12 = HEAP32[i37 >> 2] | 0;
-  if (!i12) break; else i37 = i12 + 8 | 0;
- }
- HEAP32[52] = -1;
- return;
-}
-
-function ___stdio_write(i1, i2, i3) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- i3 = i3 | 0;
- var i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0, i16 = 0, i17 = 0, i18 = 0, i19 = 0, i20 = 0, i21 = 0, i22 = 0, i23 = 0, i24 = 0;
- i4 = STACKTOP;
- STACKTOP = STACKTOP + 48 | 0;
- i5 = i4 + 16 | 0;
- i6 = i4;
- i7 = i4 + 32 | 0;
- i8 = i1 + 28 | 0;
- i9 = HEAP32[i8 >> 2] | 0;
- HEAP32[i7 >> 2] = i9;
- i10 = i1 + 20 | 0;
- i11 = (HEAP32[i10 >> 2] | 0) - i9 | 0;
- HEAP32[i7 + 4 >> 2] = i11;
- HEAP32[i7 + 8 >> 2] = i2;
- HEAP32[i7 + 12 >> 2] = i3;
- i2 = i1 + 60 | 0;
- i9 = i1 + 44 | 0;
- i12 = i7;
- i7 = 2;
- i13 = i11 + i3 | 0;
- while (1) {
-  if (!(HEAP32[2] | 0)) {
-   HEAP32[i5 >> 2] = HEAP32[i2 >> 2];
-   HEAP32[i5 + 4 >> 2] = i12;
-   HEAP32[i5 + 8 >> 2] = i7;
-   i14 = ___syscall_ret(___syscall146(146, i5 | 0) | 0) | 0;
-  } else {
-   _pthread_cleanup_push(4, i1 | 0);
-   HEAP32[i6 >> 2] = HEAP32[i2 >> 2];
-   HEAP32[i6 + 4 >> 2] = i12;
-   HEAP32[i6 + 8 >> 2] = i7;
-   i11 = ___syscall_ret(___syscall146(146, i6 | 0) | 0) | 0;
-   _pthread_cleanup_pop(0);
-   i14 = i11;
-  }
-  if ((i13 | 0) == (i14 | 0)) {
-   i15 = 6;
-   break;
-  }
-  if ((i14 | 0) < 0) {
-   i16 = i12;
-   i17 = i7;
-   i15 = 8;
-   break;
-  }
-  i11 = i13 - i14 | 0;
-  i18 = HEAP32[i12 + 4 >> 2] | 0;
-  if (i14 >>> 0 <= i18 >>> 0) if ((i7 | 0) == 2) {
-   HEAP32[i8 >> 2] = (HEAP32[i8 >> 2] | 0) + i14;
-   i19 = i18;
-   i20 = i14;
-   i21 = i12;
-   i22 = 2;
-  } else {
-   i19 = i18;
-   i20 = i14;
-   i21 = i12;
-   i22 = i7;
-  } else {
-   i23 = HEAP32[i9 >> 2] | 0;
-   HEAP32[i8 >> 2] = i23;
-   HEAP32[i10 >> 2] = i23;
-   i19 = HEAP32[i12 + 12 >> 2] | 0;
-   i20 = i14 - i18 | 0;
-   i21 = i12 + 8 | 0;
-   i22 = i7 + -1 | 0;
-  }
-  HEAP32[i21 >> 2] = (HEAP32[i21 >> 2] | 0) + i20;
-  HEAP32[i21 + 4 >> 2] = i19 - i20;
-  i12 = i21;
-  i7 = i22;
-  i13 = i11;
- }
- if ((i15 | 0) == 6) {
-  i13 = HEAP32[i9 >> 2] | 0;
-  HEAP32[i1 + 16 >> 2] = i13 + (HEAP32[i1 + 48 >> 2] | 0);
-  i9 = i13;
-  HEAP32[i8 >> 2] = i9;
-  HEAP32[i10 >> 2] = i9;
-  i24 = i3;
- } else if ((i15 | 0) == 8) {
-  HEAP32[i1 + 16 >> 2] = 0;
-  HEAP32[i8 >> 2] = 0;
-  HEAP32[i10 >> 2] = 0;
-  HEAP32[i1 >> 2] = HEAP32[i1 >> 2] | 32;
-  if ((i17 | 0) == 2) i24 = 0; else i24 = i3 - (HEAP32[i16 + 4 >> 2] | 0) | 0;
- }
- STACKTOP = i4;
- return i24 | 0;
-}
-
-function ___fwritex(i1, i2, i3) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- i3 = i3 | 0;
- var i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0, i12 = 0, i13 = 0, i14 = 0, i15 = 0;
- i4 = i3 + 16 | 0;
- i5 = HEAP32[i4 >> 2] | 0;
- if (!i5) if (!(___towrite(i3) | 0)) {
-  i6 = HEAP32[i4 >> 2] | 0;
-  i7 = 5;
- } else i8 = 0; else {
-  i6 = i5;
-  i7 = 5;
- }
- L5 : do if ((i7 | 0) == 5) {
-  i5 = i3 + 20 | 0;
-  i4 = HEAP32[i5 >> 2] | 0;
-  i9 = i4;
-  if ((i6 - i4 | 0) >>> 0 < i2 >>> 0) {
-   i8 = FUNCTION_TABLE_iiii[HEAP32[i3 + 36 >> 2] & 7](i3, i1, i2) | 0;
-   break;
-  }
-  L10 : do if ((HEAP8[i3 + 75 >> 0] | 0) > -1) {
-   i4 = i2;
-   while (1) {
-    if (!i4) {
-     i10 = i2;
-     i11 = i1;
-     i12 = i9;
-     i13 = 0;
-     break L10;
-    }
-    i14 = i4 + -1 | 0;
-    if ((HEAP8[i1 + i14 >> 0] | 0) == 10) {
-     i15 = i4;
-     break;
-    } else i4 = i14;
-   }
-   if ((FUNCTION_TABLE_iiii[HEAP32[i3 + 36 >> 2] & 7](i3, i1, i15) | 0) >>> 0 < i15 >>> 0) {
-    i8 = i15;
-    break L5;
-   }
-   i10 = i2 - i15 | 0;
-   i11 = i1 + i15 | 0;
-   i12 = HEAP32[i5 >> 2] | 0;
-   i13 = i15;
-  } else {
-   i10 = i2;
-   i11 = i1;
-   i12 = i9;
-   i13 = 0;
-  } while (0);
-  _memcpy(i12 | 0, i11 | 0, i10 | 0) | 0;
-  HEAP32[i5 >> 2] = (HEAP32[i5 >> 2] | 0) + i10;
-  i8 = i13 + i10 | 0;
- } while (0);
- return i8 | 0;
-}
-
-function _fflush(i1) {
- i1 = i1 | 0;
- var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
- do if (i1) {
-  if ((HEAP32[i1 + 76 >> 2] | 0) <= -1) {
-   i2 = ___fflush_unlocked(i1) | 0;
-   break;
-  }
-  i3 = (___lockfile(i1) | 0) == 0;
-  i4 = ___fflush_unlocked(i1) | 0;
-  if (i3) i2 = i4; else {
-   ___unlockfile(i1);
-   i2 = i4;
-  }
- } else {
-  if (!(HEAP32[14] | 0)) i5 = 0; else i5 = _fflush(HEAP32[14] | 0) | 0;
-  ___lock(36);
-  i4 = HEAP32[8] | 0;
-  if (!i4) i6 = i5; else {
-   i3 = i4;
-   i4 = i5;
-   while (1) {
-    if ((HEAP32[i3 + 76 >> 2] | 0) > -1) i7 = ___lockfile(i3) | 0; else i7 = 0;
-    if ((HEAP32[i3 + 20 >> 2] | 0) >>> 0 > (HEAP32[i3 + 28 >> 2] | 0) >>> 0) i8 = ___fflush_unlocked(i3) | 0 | i4; else i8 = i4;
-    if (i7) ___unlockfile(i3);
-    i3 = HEAP32[i3 + 56 >> 2] | 0;
-    if (!i3) {
-     i6 = i8;
-     break;
-    } else i4 = i8;
-   }
-  }
-  ___unlock(36);
-  i2 = i6;
- } while (0);
- return i2 | 0;
-}
-
-function _strlen(i1) {
- i1 = i1 | 0;
- var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
- i2 = i1;
- L1 : do if (!(i2 & 3)) {
-  i3 = i1;
-  i4 = 4;
- } else {
-  i5 = i1;
-  i6 = i2;
-  while (1) {
-   if (!(HEAP8[i5 >> 0] | 0)) {
-    i7 = i6;
-    break L1;
-   }
-   i8 = i5 + 1 | 0;
-   i6 = i8;
-   if (!(i6 & 3)) {
-    i3 = i8;
-    i4 = 4;
-    break;
-   } else i5 = i8;
-  }
- } while (0);
- if ((i4 | 0) == 4) {
-  i4 = i3;
-  while (1) {
-   i3 = HEAP32[i4 >> 2] | 0;
-   if (!((i3 & -2139062144 ^ -2139062144) & i3 + -16843009)) i4 = i4 + 4 | 0; else {
-    i9 = i3;
-    i10 = i4;
-    break;
-   }
-  }
-  if (!((i9 & 255) << 24 >> 24)) i11 = i10; else {
-   i9 = i10;
-   while (1) {
-    i10 = i9 + 1 | 0;
-    if (!(HEAP8[i10 >> 0] | 0)) {
-     i11 = i10;
-     break;
-    } else i9 = i10;
-   }
-  }
-  i7 = i11;
- }
- return i7 - i2 | 0;
-}
-
-function ___overflow(i1, i2) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- var i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0, i10 = 0, i11 = 0;
- i3 = STACKTOP;
- STACKTOP = STACKTOP + 16 | 0;
- i4 = i3;
- i5 = i2 & 255;
- HEAP8[i4 >> 0] = i5;
- i6 = i1 + 16 | 0;
- i7 = HEAP32[i6 >> 2] | 0;
- if (!i7) if (!(___towrite(i1) | 0)) {
-  i8 = HEAP32[i6 >> 2] | 0;
-  i9 = 4;
- } else i10 = -1; else {
-  i8 = i7;
-  i9 = 4;
- }
- do if ((i9 | 0) == 4) {
-  i7 = i1 + 20 | 0;
-  i6 = HEAP32[i7 >> 2] | 0;
-  if (i6 >>> 0 < i8 >>> 0 ? (i11 = i2 & 255, (i11 | 0) != (HEAP8[i1 + 75 >> 0] | 0)) : 0) {
-   HEAP32[i7 >> 2] = i6 + 1;
-   HEAP8[i6 >> 0] = i5;
-   i10 = i11;
-   break;
-  }
-  if ((FUNCTION_TABLE_iiii[HEAP32[i1 + 36 >> 2] & 7](i1, i4, 1) | 0) == 1) i10 = HEAPU8[i4 >> 0] | 0; else i10 = -1;
- } while (0);
- STACKTOP = i3;
- return i10 | 0;
-}
-
-function ___fflush_unlocked(i1) {
- i1 = i1 | 0;
- var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0;
- i2 = i1 + 20 | 0;
- i3 = i1 + 28 | 0;
- if ((HEAP32[i2 >> 2] | 0) >>> 0 > (HEAP32[i3 >> 2] | 0) >>> 0 ? (FUNCTION_TABLE_iiii[HEAP32[i1 + 36 >> 2] & 7](i1, 0, 0) | 0, (HEAP32[i2 >> 2] | 0) == 0) : 0) i4 = -1; else {
-  i5 = i1 + 4 | 0;
-  i6 = HEAP32[i5 >> 2] | 0;
-  i7 = i1 + 8 | 0;
-  i8 = HEAP32[i7 >> 2] | 0;
-  if (i6 >>> 0 < i8 >>> 0) FUNCTION_TABLE_iiii[HEAP32[i1 + 40 >> 2] & 7](i1, i6 - i8 | 0, 1) | 0;
-  HEAP32[i1 + 16 >> 2] = 0;
-  HEAP32[i3 >> 2] = 0;
-  HEAP32[i2 >> 2] = 0;
-  HEAP32[i7 >> 2] = 0;
-  HEAP32[i5 >> 2] = 0;
-  i4 = 0;
- }
- return i4 | 0;
-}
-
-function _memcpy(i1, i2, i3) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- i3 = i3 | 0;
- var i4 = 0;
- if ((i3 | 0) >= 4096) return _emscripten_memcpy_big(i1 | 0, i2 | 0, i3 | 0) | 0;
- i4 = i1 | 0;
- if ((i1 & 3) == (i2 & 3)) {
-  while (i1 & 3) {
-   if (!i3) return i4 | 0;
-   HEAP8[i1 >> 0] = HEAP8[i2 >> 0] | 0;
-   i1 = i1 + 1 | 0;
-   i2 = i2 + 1 | 0;
-   i3 = i3 - 1 | 0;
-  }
-  while ((i3 | 0) >= 4) {
-   HEAP32[i1 >> 2] = HEAP32[i2 >> 2];
-   i1 = i1 + 4 | 0;
-   i2 = i2 + 4 | 0;
-   i3 = i3 - 4 | 0;
-  }
- }
- while ((i3 | 0) > 0) {
-  HEAP8[i1 >> 0] = HEAP8[i2 >> 0] | 0;
-  i1 = i1 + 1 | 0;
-  i2 = i2 + 1 | 0;
-  i3 = i3 - 1 | 0;
- }
- return i4 | 0;
-}
-
-function runPostSets() {}
-function _memset(i1, i2, i3) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- i3 = i3 | 0;
- var i4 = 0, i5 = 0, i6 = 0, i7 = 0;
- i4 = i1 + i3 | 0;
- if ((i3 | 0) >= 20) {
-  i2 = i2 & 255;
-  i5 = i1 & 3;
-  i6 = i2 | i2 << 8 | i2 << 16 | i2 << 24;
-  i7 = i4 & ~3;
-  if (i5) {
-   i5 = i1 + 4 - i5 | 0;
-   while ((i1 | 0) < (i5 | 0)) {
-    HEAP8[i1 >> 0] = i2;
-    i1 = i1 + 1 | 0;
-   }
-  }
-  while ((i1 | 0) < (i7 | 0)) {
-   HEAP32[i1 >> 2] = i6;
-   i1 = i1 + 4 | 0;
-  }
- }
- while ((i1 | 0) < (i4 | 0)) {
-  HEAP8[i1 >> 0] = i2;
-  i1 = i1 + 1 | 0;
- }
- return i1 - i3 | 0;
-}
-
-function _puts(i1) {
- i1 = i1 | 0;
- var i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0;
- i2 = HEAP32[13] | 0;
- if ((HEAP32[i2 + 76 >> 2] | 0) > -1) i3 = ___lockfile(i2) | 0; else i3 = 0;
- do if ((_fputs(i1, i2) | 0) < 0) i4 = 1; else {
-  if ((HEAP8[i2 + 75 >> 0] | 0) != 10 ? (i5 = i2 + 20 | 0, i6 = HEAP32[i5 >> 2] | 0, i6 >>> 0 < (HEAP32[i2 + 16 >> 2] | 0) >>> 0) : 0) {
-   HEAP32[i5 >> 2] = i6 + 1;
-   HEAP8[i6 >> 0] = 10;
-   i4 = 0;
-   break;
-  }
-  i4 = (___overflow(i2, 10) | 0) < 0;
- } while (0);
- if (i3) ___unlockfile(i2);
- return i4 << 31 >> 31 | 0;
-}
-
-function ___stdio_seek(i1, i2, i3) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- i3 = i3 | 0;
- var i4 = 0, i5 = 0, i6 = 0, i7 = 0;
- i4 = STACKTOP;
- STACKTOP = STACKTOP + 32 | 0;
- i5 = i4;
- i6 = i4 + 20 | 0;
- HEAP32[i5 >> 2] = HEAP32[i1 + 60 >> 2];
- HEAP32[i5 + 4 >> 2] = 0;
- HEAP32[i5 + 8 >> 2] = i2;
- HEAP32[i5 + 12 >> 2] = i6;
- HEAP32[i5 + 16 >> 2] = i3;
- if ((___syscall_ret(___syscall140(140, i5 | 0) | 0) | 0) < 0) {
-  HEAP32[i6 >> 2] = -1;
-  i7 = -1;
- } else i7 = HEAP32[i6 >> 2] | 0;
- STACKTOP = i4;
- return i7 | 0;
-}
-
-function ___towrite(i1) {
- i1 = i1 | 0;
- var i2 = 0, i3 = 0, i4 = 0;
- i2 = i1 + 74 | 0;
- i3 = HEAP8[i2 >> 0] | 0;
- HEAP8[i2 >> 0] = i3 + 255 | i3;
- i3 = HEAP32[i1 >> 2] | 0;
- if (!(i3 & 8)) {
-  HEAP32[i1 + 8 >> 2] = 0;
-  HEAP32[i1 + 4 >> 2] = 0;
-  i2 = HEAP32[i1 + 44 >> 2] | 0;
-  HEAP32[i1 + 28 >> 2] = i2;
-  HEAP32[i1 + 20 >> 2] = i2;
-  HEAP32[i1 + 16 >> 2] = i2 + (HEAP32[i1 + 48 >> 2] | 0);
-  i4 = 0;
- } else {
-  HEAP32[i1 >> 2] = i3 | 32;
-  i4 = -1;
- }
- return i4 | 0;
-}
-
-function _fwrite(i1, i2, i3, i4) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- i3 = i3 | 0;
- i4 = i4 | 0;
- var i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;
- i5 = Math_imul(i3, i2) | 0;
- if ((HEAP32[i4 + 76 >> 2] | 0) > -1) {
-  i6 = (___lockfile(i4) | 0) == 0;
-  i7 = ___fwritex(i1, i5, i4) | 0;
-  if (i6) i8 = i7; else {
-   ___unlockfile(i4);
-   i8 = i7;
-  }
- } else i8 = ___fwritex(i1, i5, i4) | 0;
- if ((i8 | 0) == (i5 | 0)) i9 = i3; else i9 = (i8 >>> 0) / (i2 >>> 0) | 0;
- return i9 | 0;
-}
-
-function ___stdout_write(i1, i2, i3) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- i3 = i3 | 0;
- var i4 = 0, i5 = 0;
- i4 = STACKTOP;
- STACKTOP = STACKTOP + 80 | 0;
- i5 = i4;
- HEAP32[i1 + 36 >> 2] = 5;
- if ((HEAP32[i1 >> 2] & 64 | 0) == 0 ? (HEAP32[i5 >> 2] = HEAP32[i1 + 60 >> 2], HEAP32[i5 + 4 >> 2] = 21505, HEAP32[i5 + 8 >> 2] = i4 + 12, (___syscall54(54, i5 | 0) | 0) != 0) : 0) HEAP8[i1 + 75 >> 0] = -1;
- i5 = ___stdio_write(i1, i2, i3) | 0;
- STACKTOP = i4;
- return i5 | 0;
-}
-
-function copyTempDouble(i1) {
- i1 = i1 | 0;
- HEAP8[tempDoublePtr >> 0] = HEAP8[i1 >> 0];
- HEAP8[tempDoublePtr + 1 >> 0] = HEAP8[i1 + 1 >> 0];
- HEAP8[tempDoublePtr + 2 >> 0] = HEAP8[i1 + 2 >> 0];
- HEAP8[tempDoublePtr + 3 >> 0] = HEAP8[i1 + 3 >> 0];
- HEAP8[tempDoublePtr + 4 >> 0] = HEAP8[i1 + 4 >> 0];
- HEAP8[tempDoublePtr + 5 >> 0] = HEAP8[i1 + 5 >> 0];
- HEAP8[tempDoublePtr + 6 >> 0] = HEAP8[i1 + 6 >> 0];
- HEAP8[tempDoublePtr + 7 >> 0] = HEAP8[i1 + 7 >> 0];
-}
-
-function ___stdio_close(i1) {
- i1 = i1 | 0;
- var i2 = 0, i3 = 0;
- i2 = STACKTOP;
- STACKTOP = STACKTOP + 16 | 0;
- i3 = i2;
- HEAP32[i3 >> 2] = HEAP32[i1 + 60 >> 2];
- i1 = ___syscall_ret(___syscall6(6, i3 | 0) | 0) | 0;
- STACKTOP = i2;
- return i1 | 0;
-}
-
-function copyTempFloat(i1) {
- i1 = i1 | 0;
- HEAP8[tempDoublePtr >> 0] = HEAP8[i1 >> 0];
- HEAP8[tempDoublePtr + 1 >> 0] = HEAP8[i1 + 1 >> 0];
- HEAP8[tempDoublePtr + 2 >> 0] = HEAP8[i1 + 2 >> 0];
- HEAP8[tempDoublePtr + 3 >> 0] = HEAP8[i1 + 3 >> 0];
-}
-
-function ___syscall_ret(i1) {
- i1 = i1 | 0;
- var i2 = 0;
- if (i1 >>> 0 > 4294963200) {
-  HEAP32[(___errno_location() | 0) >> 2] = 0 - i1;
-  i2 = -1;
- } else i2 = i1;
- return i2 | 0;
-}
-
-function dynCall_iiii(i1, i2, i3, i4) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- i3 = i3 | 0;
- i4 = i4 | 0;
- return FUNCTION_TABLE_iiii[i1 & 7](i2 | 0, i3 | 0, i4 | 0) | 0;
-}
-function stackAlloc(i1) {
- i1 = i1 | 0;
- var i2 = 0;
- i2 = STACKTOP;
- STACKTOP = STACKTOP + i1 | 0;
- STACKTOP = STACKTOP + 15 & -16;
- return i2 | 0;
-}
-
-function ___errno_location() {
- var i1 = 0;
- if (!(HEAP32[2] | 0)) i1 = 60; else i1 = HEAP32[(_pthread_self() | 0) + 60 >> 2] | 0;
- return i1 | 0;
-}
-
-function setThrew(i1, i2) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- if (!__THREW__) {
-  __THREW__ = i1;
-  threwValue = i2;
- }
-}
-
-function _fputs(i1, i2) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- return (_fwrite(i1, _strlen(i1) | 0, 1, i2) | 0) + -1 | 0;
-}
-
-function dynCall_ii(i1, i2) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- return FUNCTION_TABLE_ii[i1 & 1](i2 | 0) | 0;
-}
-
-function _cleanup_418(i1) {
- i1 = i1 | 0;
- if (!(HEAP32[i1 + 68 >> 2] | 0)) ___unlockfile(i1);
- return;
-}
-
-function establishStackSpace(i1, i2) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- STACKTOP = i1;
- STACK_MAX = i2;
-}
-
-function dynCall_vi(i1, i2) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- FUNCTION_TABLE_vi[i1 & 7](i2 | 0);
-}
-
-function b1(i1, i2, i3) {
- i1 = i1 | 0;
- i2 = i2 | 0;
- i3 = i3 | 0;
- abort(1);
- return 0;
-}
-
-function stackRestore(i1) {
- i1 = i1 | 0;
- STACKTOP = i1;
-}
-
-function setTempRet0(i1) {
- i1 = i1 | 0;
- tempRet0 = i1;
-}
-
-function b0(i1) {
- i1 = i1 | 0;
- abort(0);
- return 0;
-}
-
-function ___unlockfile(i1) {
- i1 = i1 | 0;
- return;
-}
-
-function ___lockfile(i1) {
- i1 = i1 | 0;
- return 0;
-}
-
-function getTempRet0() {
- return tempRet0 | 0;
-}
-
-function _main() {
- _puts(672) | 0;
- return 0;
-}
-
-function stackSave() {
- return STACKTOP | 0;
-}
-
-function b2(i1) {
- i1 = i1 | 0;
- abort(2);
-}
-
-// EMSCRIPTEN_END_FUNCS
-var FUNCTION_TABLE_ii = [b0,___stdio_close];
-var FUNCTION_TABLE_iiii = [b1,b1,___stdout_write,___stdio_seek,b1,___stdio_write,b1,b1];
-var FUNCTION_TABLE_vi = [b2,b2,b2,b2,_cleanup_418,b2,b2,b2];
-
-  return { _free: _free, _main: _main, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, _fflush: _fflush, ___errno_location: ___errno_location, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, establishStackSpace: establishStackSpace, setThrew: setThrew, setTempRet0: setTempRet0, getTempRet0: getTempRet0, dynCall_ii: dynCall_ii, dynCall_iiii: dynCall_iiii, dynCall_vi: dynCall_vi };
-})
-;
diff --git a/binaryen/test/emcc_hello_world.asm.js b/binaryen/test/emcc_hello_world.asm.js
deleted file mode 100644
--- a/binaryen/test/emcc_hello_world.asm.js
+++ /dev/null
@@ -1,7101 +0,0 @@
-Module["asm"] =  (function(global, env, buffer) {
-  'almost asm';
-  
-  
-  var HEAP8 = new global.Int8Array(buffer);
-  var HEAP16 = new global.Int16Array(buffer);
-  var HEAP32 = new global.Int32Array(buffer);
-  var HEAPU8 = new global.Uint8Array(buffer);
-  var HEAPU16 = new global.Uint16Array(buffer);
-  var HEAPU32 = new global.Uint32Array(buffer);
-  var HEAPF32 = new global.Float32Array(buffer);
-  var HEAPF64 = new global.Float64Array(buffer);
-
-
-  var STACKTOP=env.STACKTOP|0;
-  var STACK_MAX=env.STACK_MAX|0;
-  var tempDoublePtr=env.tempDoublePtr|0;
-  var ABORT=env.ABORT|0;
-  var cttz_i8=env.cttz_i8|0;
-
-  var __THREW__ = 0;
-  var threwValue = 0;
-  var setjmpId = 0;
-  var undef = 0;
-  var nan = global.NaN, inf = global.Infinity;
-  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
-
-  var tempRet0 = 0;
-  var tempRet1 = 0;
-  var tempRet2 = 0;
-  var tempRet3 = 0;
-  var tempRet4 = 0;
-  var tempRet5 = 0;
-  var tempRet6 = 0;
-  var tempRet7 = 0;
-  var tempRet8 = 0;
-  var tempRet9 = 0;
-  var Math_floor=global.Math.floor;
-  var Math_abs=global.Math.abs;
-  var Math_sqrt=global.Math.sqrt;
-  var Math_pow=global.Math.pow;
-  var Math_cos=global.Math.cos;
-  var Math_sin=global.Math.sin;
-  var Math_tan=global.Math.tan;
-  var Math_acos=global.Math.acos;
-  var Math_asin=global.Math.asin;
-  var Math_atan=global.Math.atan;
-  var Math_atan2=global.Math.atan2;
-  var Math_exp=global.Math.exp;
-  var Math_log=global.Math.log;
-  var Math_ceil=global.Math.ceil;
-  var Math_imul=global.Math.imul;
-  var Math_min=global.Math.min;
-  var Math_clz32=global.Math.clz32;
-  var abort=env.abort;
-  var assert=env.assert;
-  var nullFunc_ii=env.nullFunc_ii;
-  var nullFunc_iiii=env.nullFunc_iiii;
-  var nullFunc_vi=env.nullFunc_vi;
-  var invoke_ii=env.invoke_ii;
-  var invoke_iiii=env.invoke_iiii;
-  var invoke_vi=env.invoke_vi;
-  var _pthread_cleanup_pop=env._pthread_cleanup_pop;
-  var ___lock=env.___lock;
-  var _emscripten_set_main_loop=env._emscripten_set_main_loop;
-  var _pthread_self=env._pthread_self;
-  var _abort=env._abort;
-  var _emscripten_set_main_loop_timing=env._emscripten_set_main_loop_timing;
-  var ___syscall6=env.___syscall6;
-  var _sbrk=env._sbrk;
-  var _time=env._time;
-  var ___setErrNo=env.___setErrNo;
-  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
-  var ___syscall54=env.___syscall54;
-  var ___unlock=env.___unlock;
-  var ___syscall140=env.___syscall140;
-  var _pthread_cleanup_push=env._pthread_cleanup_push;
-  var _sysconf=env._sysconf;
-  var ___syscall146=env.___syscall146;
-  var _llvm_cttz_i32=env._llvm_cttz_i32;
-  var tempFloat = 0.0;
-
-// EMSCRIPTEN_START_FUNCS
-function stackAlloc(size) {
-  size = size|0;
-  var ret = 0;
-  ret = STACKTOP;
-  STACKTOP = (STACKTOP + size)|0;
-  STACKTOP = (STACKTOP + 15)&-16;
-if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
-
-  return ret|0;
-}
-function stackSave() {
-  return STACKTOP|0;
-}
-function stackRestore(top) {
-  top = top|0;
-  STACKTOP = top;
-}
-function establishStackSpace(stackBase, stackMax) {
-  stackBase = stackBase|0;
-  stackMax = stackMax|0;
-  STACKTOP = stackBase;
-  STACK_MAX = stackMax;
-}
-
-function setThrew(threw, value) {
-  threw = threw|0;
-  value = value|0;
-  if ((__THREW__|0) == 0) {
-    __THREW__ = threw;
-    threwValue = value;
-  }
-}
-function copyTempFloat(ptr) {
-  ptr = ptr|0;
-  HEAP8[tempDoublePtr>>0] = HEAP8[ptr>>0];
-  HEAP8[tempDoublePtr+1>>0] = HEAP8[ptr+1>>0];
-  HEAP8[tempDoublePtr+2>>0] = HEAP8[ptr+2>>0];
-  HEAP8[tempDoublePtr+3>>0] = HEAP8[ptr+3>>0];
-}
-function copyTempDouble(ptr) {
-  ptr = ptr|0;
-  HEAP8[tempDoublePtr>>0] = HEAP8[ptr>>0];
-  HEAP8[tempDoublePtr+1>>0] = HEAP8[ptr+1>>0];
-  HEAP8[tempDoublePtr+2>>0] = HEAP8[ptr+2>>0];
-  HEAP8[tempDoublePtr+3>>0] = HEAP8[ptr+3>>0];
-  HEAP8[tempDoublePtr+4>>0] = HEAP8[ptr+4>>0];
-  HEAP8[tempDoublePtr+5>>0] = HEAP8[ptr+5>>0];
-  HEAP8[tempDoublePtr+6>>0] = HEAP8[ptr+6>>0];
-  HEAP8[tempDoublePtr+7>>0] = HEAP8[ptr+7>>0];
-}
-
-function setTempRet0(value) {
-  value = value|0;
-  tempRet0 = value;
-}
-function getTempRet0() {
-  return tempRet0|0;
-}
-
-function _main() {
- var $retval = 0, $vararg_buffer = 0, label = 0, sp = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 16|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
- $vararg_buffer = sp;
- $retval = 0;
- (_printf(672,$vararg_buffer)|0);
- STACKTOP = sp;return 0;
-}
-function _frexp($x,$e) {
- $x = +$x;
- $e = $e|0;
- var $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0.0, $call = 0.0, $conv = 0, $mul = 0.0, $retval$0 = 0.0, $storemerge = 0, $sub = 0, $sub8 = 0, $tobool1 = 0, $x$addr$0 = 0.0, label = 0, sp = 0;
- sp = STACKTOP;
- HEAPF64[tempDoublePtr>>3] = $x;$0 = HEAP32[tempDoublePtr>>2]|0;
- $1 = HEAP32[tempDoublePtr+4>>2]|0;
- $2 = (_bitshift64Lshr(($0|0),($1|0),52)|0);
- $3 = tempRet0;
- $conv = $2 & 2047;
- switch ($conv|0) {
- case 0:  {
-  $tobool1 = $x != 0.0;
-  if ($tobool1) {
-   $mul = $x * 1.8446744073709552E+19;
-   $call = (+_frexp($mul,$e));
-   $4 = HEAP32[$e>>2]|0;
-   $sub = (($4) + -64)|0;
-   $storemerge = $sub;$x$addr$0 = $call;
-  } else {
-   $storemerge = 0;$x$addr$0 = $x;
-  }
-  HEAP32[$e>>2] = $storemerge;
-  $retval$0 = $x$addr$0;
-  break;
- }
- case 2047:  {
-  $retval$0 = $x;
-  break;
- }
- default: {
-  $sub8 = (($conv) + -1022)|0;
-  HEAP32[$e>>2] = $sub8;
-  $5 = $1 & -2146435073;
-  $6 = $5 | 1071644672;
-  HEAP32[tempDoublePtr>>2] = $0;HEAP32[tempDoublePtr+4>>2] = $6;$7 = +HEAPF64[tempDoublePtr>>3];
-  $retval$0 = $7;
- }
- }
- return (+$retval$0);
-}
-function _frexpl($x,$e) {
- $x = +$x;
- $e = $e|0;
- var $call = 0.0, label = 0, sp = 0;
- sp = STACKTOP;
- $call = (+_frexp($x,$e));
- return (+$call);
-}
-function _strerror($e) {
- $e = $e|0;
- var $0 = 0, $1 = 0, $arrayidx = 0, $cmp = 0, $conv = 0, $dec = 0, $i$012 = 0, $i$012$lcssa = 0, $i$111 = 0, $inc = 0, $incdec$ptr = 0, $incdec$ptr$lcssa = 0, $s$0$lcssa = 0, $s$010 = 0, $s$1 = 0, $tobool = 0, $tobool5 = 0, $tobool5$9 = 0, $tobool8 = 0, label = 0;
- var sp = 0;
- sp = STACKTOP;
- $i$012 = 0;
- while(1) {
-  $arrayidx = (687 + ($i$012)|0);
-  $0 = HEAP8[$arrayidx>>0]|0;
-  $conv = $0&255;
-  $cmp = ($conv|0)==($e|0);
-  if ($cmp) {
-   $i$012$lcssa = $i$012;
-   label = 2;
-   break;
-  }
-  $inc = (($i$012) + 1)|0;
-  $tobool = ($inc|0)==(87);
-  if ($tobool) {
-   $i$111 = 87;$s$010 = 775;
-   label = 5;
-   break;
-  } else {
-   $i$012 = $inc;
-  }
- }
- if ((label|0) == 2) {
-  $tobool5$9 = ($i$012$lcssa|0)==(0);
-  if ($tobool5$9) {
-   $s$0$lcssa = 775;
-  } else {
-   $i$111 = $i$012$lcssa;$s$010 = 775;
-   label = 5;
-  }
- }
- if ((label|0) == 5) {
-  while(1) {
-   label = 0;
-   $s$1 = $s$010;
-   while(1) {
-    $1 = HEAP8[$s$1>>0]|0;
-    $tobool8 = ($1<<24>>24)==(0);
-    $incdec$ptr = ((($s$1)) + 1|0);
-    if ($tobool8) {
-     $incdec$ptr$lcssa = $incdec$ptr;
-     break;
-    } else {
-     $s$1 = $incdec$ptr;
-    }
-   }
-   $dec = (($i$111) + -1)|0;
-   $tobool5 = ($dec|0)==(0);
-   if ($tobool5) {
-    $s$0$lcssa = $incdec$ptr$lcssa;
-    break;
-   } else {
-    $i$111 = $dec;$s$010 = $incdec$ptr$lcssa;
-    label = 5;
-   }
-  }
- }
- return ($s$0$lcssa|0);
-}
-function ___errno_location() {
- var $0 = 0, $1 = 0, $call$i = 0, $errno_ptr = 0, $retval$0 = 0, $tobool = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $0 = HEAP32[4]|0;
- $tobool = ($0|0)==(0|0);
- if ($tobool) {
-  $retval$0 = 60;
- } else {
-  $call$i = (_pthread_self()|0);
-  $errno_ptr = ((($call$i)) + 60|0);
-  $1 = HEAP32[$errno_ptr>>2]|0;
-  $retval$0 = $1;
- }
- return ($retval$0|0);
-}
-function ___stdio_close($f) {
- $f = $f|0;
- var $0 = 0, $call = 0, $call1 = 0, $fd = 0, $vararg_buffer = 0, label = 0, sp = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 16|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
- $vararg_buffer = sp;
- $fd = ((($f)) + 60|0);
- $0 = HEAP32[$fd>>2]|0;
- HEAP32[$vararg_buffer>>2] = $0;
- $call = (___syscall6(6,($vararg_buffer|0))|0);
- $call1 = (___syscall_ret($call)|0);
- STACKTOP = sp;return ($call1|0);
-}
-function ___stdout_write($f,$buf,$len) {
- $f = $f|0;
- $buf = $buf|0;
- $len = $len|0;
- var $0 = 0, $1 = 0, $and = 0, $call = 0, $call3 = 0, $fd = 0, $lbf = 0, $tio = 0, $tobool = 0, $tobool2 = 0, $vararg_buffer = 0, $vararg_ptr1 = 0, $vararg_ptr2 = 0, $write = 0, label = 0, sp = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 80|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
- $vararg_buffer = sp;
- $tio = sp + 12|0;
- $write = ((($f)) + 36|0);
- HEAP32[$write>>2] = 4;
- $0 = HEAP32[$f>>2]|0;
- $and = $0 & 64;
- $tobool = ($and|0)==(0);
- if ($tobool) {
-  $fd = ((($f)) + 60|0);
-  $1 = HEAP32[$fd>>2]|0;
-  HEAP32[$vararg_buffer>>2] = $1;
-  $vararg_ptr1 = ((($vararg_buffer)) + 4|0);
-  HEAP32[$vararg_ptr1>>2] = 21505;
-  $vararg_ptr2 = ((($vararg_buffer)) + 8|0);
-  HEAP32[$vararg_ptr2>>2] = $tio;
-  $call = (___syscall54(54,($vararg_buffer|0))|0);
-  $tobool2 = ($call|0)==(0);
-  if (!($tobool2)) {
-   $lbf = ((($f)) + 75|0);
-   HEAP8[$lbf>>0] = -1;
-  }
- }
- $call3 = (___stdio_write($f,$buf,$len)|0);
- STACKTOP = sp;return ($call3|0);
-}
-function ___stdio_seek($f,$off,$whence) {
- $f = $f|0;
- $off = $off|0;
- $whence = $whence|0;
- var $$pre = 0, $0 = 0, $1 = 0, $call = 0, $call1 = 0, $cmp = 0, $fd = 0, $ret = 0, $vararg_buffer = 0, $vararg_ptr1 = 0, $vararg_ptr2 = 0, $vararg_ptr3 = 0, $vararg_ptr4 = 0, label = 0, sp = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 32|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
- $vararg_buffer = sp;
- $ret = sp + 20|0;
- $fd = ((($f)) + 60|0);
- $0 = HEAP32[$fd>>2]|0;
- HEAP32[$vararg_buffer>>2] = $0;
- $vararg_ptr1 = ((($vararg_buffer)) + 4|0);
- HEAP32[$vararg_ptr1>>2] = 0;
- $vararg_ptr2 = ((($vararg_buffer)) + 8|0);
- HEAP32[$vararg_ptr2>>2] = $off;
- $vararg_ptr3 = ((($vararg_buffer)) + 12|0);
- HEAP32[$vararg_ptr3>>2] = $ret;
- $vararg_ptr4 = ((($vararg_buffer)) + 16|0);
- HEAP32[$vararg_ptr4>>2] = $whence;
- $call = (___syscall140(140,($vararg_buffer|0))|0);
- $call1 = (___syscall_ret($call)|0);
- $cmp = ($call1|0)<(0);
- if ($cmp) {
-  HEAP32[$ret>>2] = -1;
-  $1 = -1;
- } else {
-  $$pre = HEAP32[$ret>>2]|0;
-  $1 = $$pre;
- }
- STACKTOP = sp;return ($1|0);
-}
-function _fflush($f) {
- $f = $f|0;
- var $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $call = 0, $call1 = 0, $call1$18 = 0, $call16 = 0, $call22 = 0, $call7 = 0, $cmp = 0, $cmp14 = 0, $cmp20 = 0, $cond10 = 0, $cond19 = 0, $f$addr$0 = 0, $f$addr$0$19 = 0, $f$addr$022 = 0;
- var $lock = 0, $lock13 = 0, $next = 0, $or = 0, $phitmp = 0, $r$0$lcssa = 0, $r$021 = 0, $r$1 = 0, $retval$0 = 0, $tobool = 0, $tobool11 = 0, $tobool11$20 = 0, $tobool24 = 0, $tobool5 = 0, $wbase = 0, $wpos = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $tobool = ($f|0)==(0|0);
- do {
-  if ($tobool) {
-   $1 = HEAP32[3]|0;
-   $tobool5 = ($1|0)==(0|0);
-   if ($tobool5) {
-    $cond10 = 0;
-   } else {
-    $2 = HEAP32[3]|0;
-    $call7 = (_fflush($2)|0);
-    $cond10 = $call7;
-   }
-   ___lock(((44)|0));
-   $f$addr$0$19 = HEAP32[(40)>>2]|0;
-   $tobool11$20 = ($f$addr$0$19|0)==(0|0);
-   if ($tobool11$20) {
-    $r$0$lcssa = $cond10;
-   } else {
-    $f$addr$022 = $f$addr$0$19;$r$021 = $cond10;
-    while(1) {
-     $lock13 = ((($f$addr$022)) + 76|0);
-     $3 = HEAP32[$lock13>>2]|0;
-     $cmp14 = ($3|0)>(-1);
-     if ($cmp14) {
-      $call16 = (___lockfile($f$addr$022)|0);
-      $cond19 = $call16;
-     } else {
-      $cond19 = 0;
-     }
-     $wpos = ((($f$addr$022)) + 20|0);
-     $4 = HEAP32[$wpos>>2]|0;
-     $wbase = ((($f$addr$022)) + 28|0);
-     $5 = HEAP32[$wbase>>2]|0;
-     $cmp20 = ($4>>>0)>($5>>>0);
-     if ($cmp20) {
-      $call22 = (___fflush_unlocked($f$addr$022)|0);
-      $or = $call22 | $r$021;
-      $r$1 = $or;
-     } else {
-      $r$1 = $r$021;
-     }
-     $tobool24 = ($cond19|0)==(0);
-     if (!($tobool24)) {
-      ___unlockfile($f$addr$022);
-     }
-     $next = ((($f$addr$022)) + 56|0);
-     $f$addr$0 = HEAP32[$next>>2]|0;
-     $tobool11 = ($f$addr$0|0)==(0|0);
-     if ($tobool11) {
-      $r$0$lcssa = $r$1;
-      break;
-     } else {
-      $f$addr$022 = $f$addr$0;$r$021 = $r$1;
-     }
-    }
-   }
-   ___unlock(((44)|0));
-   $retval$0 = $r$0$lcssa;
-  } else {
-   $lock = ((($f)) + 76|0);
-   $0 = HEAP32[$lock>>2]|0;
-   $cmp = ($0|0)>(-1);
-   if (!($cmp)) {
-    $call1$18 = (___fflush_unlocked($f)|0);
-    $retval$0 = $call1$18;
-    break;
-   }
-   $call = (___lockfile($f)|0);
-   $phitmp = ($call|0)==(0);
-   $call1 = (___fflush_unlocked($f)|0);
-   if ($phitmp) {
-    $retval$0 = $call1;
-   } else {
-    ___unlockfile($f);
-    $retval$0 = $call1;
-   }
-  }
- } while(0);
- return ($retval$0|0);
-}
-function _printf($fmt,$varargs) {
- $fmt = $fmt|0;
- $varargs = $varargs|0;
- var $0 = 0, $ap = 0, $call = 0, label = 0, sp = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 16|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
- $ap = sp;
- HEAP32[$ap>>2] = $varargs;
- $0 = HEAP32[2]|0;
- $call = (_vfprintf($0,$fmt,$ap)|0);
- STACKTOP = sp;return ($call|0);
-}
-function ___lockfile($f) {
- $f = $f|0;
- var label = 0, sp = 0;
- sp = STACKTOP;
- return 0;
-}
-function ___unlockfile($f) {
- $f = $f|0;
- var label = 0, sp = 0;
- sp = STACKTOP;
- return;
-}
-function ___stdio_write($f,$buf,$len) {
- $f = $f|0;
- $buf = $buf|0;
- $len = $len|0;
- var $$pre = 0, $0 = 0, $1 = 0, $10 = 0, $11 = 0, $12 = 0, $13 = 0, $14 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0, $8 = 0, $9 = 0, $add = 0, $add$ptr = 0, $add$ptr41 = 0, $add$ptr46 = 0;
- var $buf31 = 0, $buf_size = 0, $call = 0, $call10 = 0, $call7 = 0, $call9 = 0, $cmp = 0, $cmp17 = 0, $cmp22 = 0, $cmp29 = 0, $cmp38 = 0, $cnt$0 = 0, $cnt$1 = 0, $dec = 0, $fd8 = 0, $incdec$ptr = 0, $iov$0 = 0, $iov$0$lcssa57 = 0, $iov$1 = 0, $iov_base2 = 0;
- var $iov_len = 0, $iov_len24 = 0, $iov_len28 = 0, $iov_len3 = 0, $iov_len50 = 0, $iov_len50$phi$trans$insert = 0, $iovcnt$0 = 0, $iovcnt$0$lcssa58 = 0, $iovcnt$1 = 0, $iovs = 0, $or = 0, $rem$0 = 0, $retval$0 = 0, $sub = 0, $sub$ptr$sub = 0, $sub26 = 0, $sub36 = 0, $sub51 = 0, $tobool = 0, $vararg_buffer = 0;
- var $vararg_buffer3 = 0, $vararg_ptr1 = 0, $vararg_ptr2 = 0, $vararg_ptr6 = 0, $vararg_ptr7 = 0, $wbase = 0, $wend = 0, $wend19 = 0, $wpos = 0, label = 0, sp = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 48|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
- $vararg_buffer3 = sp + 16|0;
- $vararg_buffer = sp;
- $iovs = sp + 32|0;
- $wbase = ((($f)) + 28|0);
- $0 = HEAP32[$wbase>>2]|0;
- HEAP32[$iovs>>2] = $0;
- $iov_len = ((($iovs)) + 4|0);
- $wpos = ((($f)) + 20|0);
- $1 = HEAP32[$wpos>>2]|0;
- $sub$ptr$sub = (($1) - ($0))|0;
- HEAP32[$iov_len>>2] = $sub$ptr$sub;
- $iov_base2 = ((($iovs)) + 8|0);
- HEAP32[$iov_base2>>2] = $buf;
- $iov_len3 = ((($iovs)) + 12|0);
- HEAP32[$iov_len3>>2] = $len;
- $add = (($sub$ptr$sub) + ($len))|0;
- $fd8 = ((($f)) + 60|0);
- $buf31 = ((($f)) + 44|0);
- $iov$0 = $iovs;$iovcnt$0 = 2;$rem$0 = $add;
- while(1) {
-  $2 = HEAP32[4]|0;
-  $tobool = ($2|0)==(0|0);
-  if ($tobool) {
-   $4 = HEAP32[$fd8>>2]|0;
-   HEAP32[$vararg_buffer3>>2] = $4;
-   $vararg_ptr6 = ((($vararg_buffer3)) + 4|0);
-   HEAP32[$vararg_ptr6>>2] = $iov$0;
-   $vararg_ptr7 = ((($vararg_buffer3)) + 8|0);
-   HEAP32[$vararg_ptr7>>2] = $iovcnt$0;
-   $call9 = (___syscall146(146,($vararg_buffer3|0))|0);
-   $call10 = (___syscall_ret($call9)|0);
-   $cnt$0 = $call10;
-  } else {
-   _pthread_cleanup_push((5|0),($f|0));
-   $3 = HEAP32[$fd8>>2]|0;
-   HEAP32[$vararg_buffer>>2] = $3;
-   $vararg_ptr1 = ((($vararg_buffer)) + 4|0);
-   HEAP32[$vararg_ptr1>>2] = $iov$0;
-   $vararg_ptr2 = ((($vararg_buffer)) + 8|0);
-   HEAP32[$vararg_ptr2>>2] = $iovcnt$0;
-   $call = (___syscall146(146,($vararg_buffer|0))|0);
-   $call7 = (___syscall_ret($call)|0);
-   _pthread_cleanup_pop(0);
-   $cnt$0 = $call7;
-  }
-  $cmp = ($rem$0|0)==($cnt$0|0);
-  if ($cmp) {
-   label = 6;
-   break;
-  }
-  $cmp17 = ($cnt$0|0)<(0);
-  if ($cmp17) {
-   $iov$0$lcssa57 = $iov$0;$iovcnt$0$lcssa58 = $iovcnt$0;
-   label = 8;
-   break;
-  }
-  $sub26 = (($rem$0) - ($cnt$0))|0;
-  $iov_len28 = ((($iov$0)) + 4|0);
-  $10 = HEAP32[$iov_len28>>2]|0;
-  $cmp29 = ($cnt$0>>>0)>($10>>>0);
-  if ($cmp29) {
-   $11 = HEAP32[$buf31>>2]|0;
-   HEAP32[$wbase>>2] = $11;
-   HEAP32[$wpos>>2] = $11;
-   $sub36 = (($cnt$0) - ($10))|0;
-   $incdec$ptr = ((($iov$0)) + 8|0);
-   $dec = (($iovcnt$0) + -1)|0;
-   $iov_len50$phi$trans$insert = ((($iov$0)) + 12|0);
-   $$pre = HEAP32[$iov_len50$phi$trans$insert>>2]|0;
-   $14 = $$pre;$cnt$1 = $sub36;$iov$1 = $incdec$ptr;$iovcnt$1 = $dec;
-  } else {
-   $cmp38 = ($iovcnt$0|0)==(2);
-   if ($cmp38) {
-    $12 = HEAP32[$wbase>>2]|0;
-    $add$ptr41 = (($12) + ($cnt$0)|0);
-    HEAP32[$wbase>>2] = $add$ptr41;
-    $14 = $10;$cnt$1 = $cnt$0;$iov$1 = $iov$0;$iovcnt$1 = 2;
-   } else {
-    $14 = $10;$cnt$1 = $cnt$0;$iov$1 = $iov$0;$iovcnt$1 = $iovcnt$0;
-   }
-  }
-  $13 = HEAP32[$iov$1>>2]|0;
-  $add$ptr46 = (($13) + ($cnt$1)|0);
-  HEAP32[$iov$1>>2] = $add$ptr46;
-  $iov_len50 = ((($iov$1)) + 4|0);
-  $sub51 = (($14) - ($cnt$1))|0;
-  HEAP32[$iov_len50>>2] = $sub51;
-  $iov$0 = $iov$1;$iovcnt$0 = $iovcnt$1;$rem$0 = $sub26;
- }
- if ((label|0) == 6) {
-  $5 = HEAP32[$buf31>>2]|0;
-  $buf_size = ((($f)) + 48|0);
-  $6 = HEAP32[$buf_size>>2]|0;
-  $add$ptr = (($5) + ($6)|0);
-  $wend = ((($f)) + 16|0);
-  HEAP32[$wend>>2] = $add$ptr;
-  $7 = $5;
-  HEAP32[$wbase>>2] = $7;
-  HEAP32[$wpos>>2] = $7;
-  $retval$0 = $len;
- }
- else if ((label|0) == 8) {
-  $wend19 = ((($f)) + 16|0);
-  HEAP32[$wend19>>2] = 0;
-  HEAP32[$wbase>>2] = 0;
-  HEAP32[$wpos>>2] = 0;
-  $8 = HEAP32[$f>>2]|0;
-  $or = $8 | 32;
-  HEAP32[$f>>2] = $or;
-  $cmp22 = ($iovcnt$0$lcssa58|0)==(2);
-  if ($cmp22) {
-   $retval$0 = 0;
-  } else {
-   $iov_len24 = ((($iov$0$lcssa57)) + 4|0);
-   $9 = HEAP32[$iov_len24>>2]|0;
-   $sub = (($len) - ($9))|0;
-   $retval$0 = $sub;
-  }
- }
- STACKTOP = sp;return ($retval$0|0);
-}
-function _vfprintf($f,$fmt,$ap) {
- $f = $f|0;
- $fmt = $fmt|0;
- $ap = $ap|0;
- var $$call21 = 0, $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0, $add$ptr = 0, $and = 0, $and11 = 0, $and36 = 0, $ap2 = 0, $buf = 0, $buf_size = 0, $call = 0, $call21 = 0, $call21$30 = 0, $call6 = 0;
- var $cmp = 0, $cmp5 = 0, $cmp7 = 0, $cond = 0, $internal_buf = 0, $lock = 0, $mode = 0, $nl_arg = 0, $nl_type = 0, $or = 0, $ret$1 = 0, $ret$1$ = 0, $retval$0 = 0, $tobool = 0, $tobool22 = 0, $tobool26 = 0, $tobool37 = 0, $tobool41 = 0, $vacopy_currentptr = 0, $wbase = 0;
- var $wend = 0, $wpos = 0, $write = 0, dest = 0, label = 0, sp = 0, stop = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 224|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
- $ap2 = sp + 120|0;
- $nl_type = sp + 80|0;
- $nl_arg = sp;
- $internal_buf = sp + 136|0;
- dest=$nl_type; stop=dest+40|0; do { HEAP32[dest>>2]=0|0; dest=dest+4|0; } while ((dest|0) < (stop|0));
- $vacopy_currentptr = HEAP32[$ap>>2]|0;
- HEAP32[$ap2>>2] = $vacopy_currentptr;
- $call = (_printf_core(0,$fmt,$ap2,$nl_arg,$nl_type)|0);
- $cmp = ($call|0)<(0);
- if ($cmp) {
-  $retval$0 = -1;
- } else {
-  $lock = ((($f)) + 76|0);
-  $0 = HEAP32[$lock>>2]|0;
-  $cmp5 = ($0|0)>(-1);
-  if ($cmp5) {
-   $call6 = (___lockfile($f)|0);
-   $cond = $call6;
-  } else {
-   $cond = 0;
-  }
-  $1 = HEAP32[$f>>2]|0;
-  $and = $1 & 32;
-  $mode = ((($f)) + 74|0);
-  $2 = HEAP8[$mode>>0]|0;
-  $cmp7 = ($2<<24>>24)<(1);
-  if ($cmp7) {
-   $and11 = $1 & -33;
-   HEAP32[$f>>2] = $and11;
-  }
-  $buf_size = ((($f)) + 48|0);
-  $3 = HEAP32[$buf_size>>2]|0;
-  $tobool = ($3|0)==(0);
-  if ($tobool) {
-   $buf = ((($f)) + 44|0);
-   $4 = HEAP32[$buf>>2]|0;
-   HEAP32[$buf>>2] = $internal_buf;
-   $wbase = ((($f)) + 28|0);
-   HEAP32[$wbase>>2] = $internal_buf;
-   $wpos = ((($f)) + 20|0);
-   HEAP32[$wpos>>2] = $internal_buf;
-   HEAP32[$buf_size>>2] = 80;
-   $add$ptr = ((($internal_buf)) + 80|0);
-   $wend = ((($f)) + 16|0);
-   HEAP32[$wend>>2] = $add$ptr;
-   $call21 = (_printf_core($f,$fmt,$ap2,$nl_arg,$nl_type)|0);
-   $tobool22 = ($4|0)==(0|0);
-   if ($tobool22) {
-    $ret$1 = $call21;
-   } else {
-    $write = ((($f)) + 36|0);
-    $5 = HEAP32[$write>>2]|0;
-    (FUNCTION_TABLE_iiii[$5 & 7]($f,0,0)|0);
-    $6 = HEAP32[$wpos>>2]|0;
-    $tobool26 = ($6|0)==(0|0);
-    $$call21 = $tobool26 ? -1 : $call21;
-    HEAP32[$buf>>2] = $4;
-    HEAP32[$buf_size>>2] = 0;
-    HEAP32[$wend>>2] = 0;
-    HEAP32[$wbase>>2] = 0;
-    HEAP32[$wpos>>2] = 0;
-    $ret$1 = $$call21;
-   }
-  } else {
-   $call21$30 = (_printf_core($f,$fmt,$ap2,$nl_arg,$nl_type)|0);
-   $ret$1 = $call21$30;
-  }
-  $7 = HEAP32[$f>>2]|0;
-  $and36 = $7 & 32;
-  $tobool37 = ($and36|0)==(0);
-  $ret$1$ = $tobool37 ? $ret$1 : -1;
-  $or = $7 | $and;
-  HEAP32[$f>>2] = $or;
-  $tobool41 = ($cond|0)==(0);
-  if (!($tobool41)) {
-   ___unlockfile($f);
-  }
-  $retval$0 = $ret$1$;
- }
- STACKTOP = sp;return ($retval$0|0);
-}
-function ___fwritex($s,$l,$f) {
- $s = $s|0;
- $l = $l|0;
- $f = $f|0;
- var $$pre = 0, $$pre31 = 0, $0 = 0, $1 = 0, $10 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0, $8 = 0, $9 = 0, $add = 0, $add$ptr = 0, $add$ptr26 = 0, $arrayidx = 0, $call = 0, $call16 = 0, $call4 = 0;
- var $cmp = 0, $cmp11 = 0, $cmp17 = 0, $cmp6 = 0, $i$0 = 0, $i$0$lcssa36 = 0, $i$1 = 0, $l$addr$0 = 0, $lbf = 0, $retval$0 = 0, $s$addr$0 = 0, $sub = 0, $sub$ptr$sub = 0, $sub21 = 0, $tobool = 0, $tobool1 = 0, $tobool9 = 0, $wend = 0, $wpos = 0, $write = 0;
- var $write15 = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $wend = ((($f)) + 16|0);
- $0 = HEAP32[$wend>>2]|0;
- $tobool = ($0|0)==(0|0);
- if ($tobool) {
-  $call = (___towrite($f)|0);
-  $tobool1 = ($call|0)==(0);
-  if ($tobool1) {
-   $$pre = HEAP32[$wend>>2]|0;
-   $3 = $$pre;
-   label = 5;
-  } else {
-   $retval$0 = 0;
-  }
- } else {
-  $1 = $0;
-  $3 = $1;
-  label = 5;
- }
- L5: do {
-  if ((label|0) == 5) {
-   $wpos = ((($f)) + 20|0);
-   $2 = HEAP32[$wpos>>2]|0;
-   $sub$ptr$sub = (($3) - ($2))|0;
-   $cmp = ($sub$ptr$sub>>>0)<($l>>>0);
-   $4 = $2;
-   if ($cmp) {
-    $write = ((($f)) + 36|0);
-    $5 = HEAP32[$write>>2]|0;
-    $call4 = (FUNCTION_TABLE_iiii[$5 & 7]($f,$s,$l)|0);
-    $retval$0 = $call4;
-    break;
-   }
-   $lbf = ((($f)) + 75|0);
-   $6 = HEAP8[$lbf>>0]|0;
-   $cmp6 = ($6<<24>>24)>(-1);
-   L10: do {
-    if ($cmp6) {
-     $i$0 = $l;
-     while(1) {
-      $tobool9 = ($i$0|0)==(0);
-      if ($tobool9) {
-       $9 = $4;$i$1 = 0;$l$addr$0 = $l;$s$addr$0 = $s;
-       break L10;
-      }
-      $sub = (($i$0) + -1)|0;
-      $arrayidx = (($s) + ($sub)|0);
-      $7 = HEAP8[$arrayidx>>0]|0;
-      $cmp11 = ($7<<24>>24)==(10);
-      if ($cmp11) {
-       $i$0$lcssa36 = $i$0;
-       break;
-      } else {
-       $i$0 = $sub;
-      }
-     }
-     $write15 = ((($f)) + 36|0);
-     $8 = HEAP32[$write15>>2]|0;
-     $call16 = (FUNCTION_TABLE_iiii[$8 & 7]($f,$s,$i$0$lcssa36)|0);
-     $cmp17 = ($call16>>>0)<($i$0$lcssa36>>>0);
-     if ($cmp17) {
-      $retval$0 = $i$0$lcssa36;
-      break L5;
-     }
-     $add$ptr = (($s) + ($i$0$lcssa36)|0);
-     $sub21 = (($l) - ($i$0$lcssa36))|0;
-     $$pre31 = HEAP32[$wpos>>2]|0;
-     $9 = $$pre31;$i$1 = $i$0$lcssa36;$l$addr$0 = $sub21;$s$addr$0 = $add$ptr;
-    } else {
-     $9 = $4;$i$1 = 0;$l$addr$0 = $l;$s$addr$0 = $s;
-    }
-   } while(0);
-   _memcpy(($9|0),($s$addr$0|0),($l$addr$0|0))|0;
-   $10 = HEAP32[$wpos>>2]|0;
-   $add$ptr26 = (($10) + ($l$addr$0)|0);
-   HEAP32[$wpos>>2] = $add$ptr26;
-   $add = (($i$1) + ($l$addr$0))|0;
-   $retval$0 = $add;
-  }
- } while(0);
- return ($retval$0|0);
-}
-function ___towrite($f) {
- $f = $f|0;
- var $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $add$ptr = 0, $and = 0, $buf = 0, $buf_size = 0, $conv = 0, $conv3 = 0, $mode = 0, $or = 0, $or5 = 0, $rend = 0, $retval$0 = 0, $rpos = 0, $sub = 0, $tobool = 0, $wbase = 0;
- var $wend = 0, $wpos = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $mode = ((($f)) + 74|0);
- $0 = HEAP8[$mode>>0]|0;
- $conv = $0 << 24 >> 24;
- $sub = (($conv) + 255)|0;
- $or = $sub | $conv;
- $conv3 = $or&255;
- HEAP8[$mode>>0] = $conv3;
- $1 = HEAP32[$f>>2]|0;
- $and = $1 & 8;
- $tobool = ($and|0)==(0);
- if ($tobool) {
-  $rend = ((($f)) + 8|0);
-  HEAP32[$rend>>2] = 0;
-  $rpos = ((($f)) + 4|0);
-  HEAP32[$rpos>>2] = 0;
-  $buf = ((($f)) + 44|0);
-  $2 = HEAP32[$buf>>2]|0;
-  $wbase = ((($f)) + 28|0);
-  HEAP32[$wbase>>2] = $2;
-  $wpos = ((($f)) + 20|0);
-  HEAP32[$wpos>>2] = $2;
-  $3 = $2;
-  $buf_size = ((($f)) + 48|0);
-  $4 = HEAP32[$buf_size>>2]|0;
-  $add$ptr = (($3) + ($4)|0);
-  $wend = ((($f)) + 16|0);
-  HEAP32[$wend>>2] = $add$ptr;
-  $retval$0 = 0;
- } else {
-  $or5 = $1 | 32;
-  HEAP32[$f>>2] = $or5;
-  $retval$0 = -1;
- }
- return ($retval$0|0);
-}
-function _wcrtomb($s,$wc,$st) {
- $s = $s|0;
- $wc = $wc|0;
- $st = $st|0;
- var $0 = 0, $and = 0, $and19 = 0, $and23 = 0, $and36 = 0, $and41 = 0, $and45 = 0, $call = 0, $cmp = 0, $cmp11 = 0, $cmp2 = 0, $cmp28 = 0, $cmp9 = 0, $conv = 0, $conv16 = 0, $conv21 = 0, $conv25 = 0, $conv33 = 0, $conv38 = 0, $conv43 = 0;
- var $conv47 = 0, $conv5 = 0, $conv7 = 0, $incdec$ptr = 0, $incdec$ptr17 = 0, $incdec$ptr22 = 0, $incdec$ptr34 = 0, $incdec$ptr39 = 0, $incdec$ptr44 = 0, $or = 0, $or$cond = 0, $or15 = 0, $or20 = 0, $or24 = 0, $or32 = 0, $or37 = 0, $or42 = 0, $or46 = 0, $or6 = 0, $retval$0 = 0;
- var $shr$28 = 0, $shr14$26 = 0, $shr18$27 = 0, $shr31$23 = 0, $shr35$24 = 0, $shr40$25 = 0, $sub27 = 0, $tobool = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $tobool = ($s|0)==(0|0);
- do {
-  if ($tobool) {
-   $retval$0 = 1;
-  } else {
-   $cmp = ($wc>>>0)<(128);
-   if ($cmp) {
-    $conv = $wc&255;
-    HEAP8[$s>>0] = $conv;
-    $retval$0 = 1;
-    break;
-   }
-   $cmp2 = ($wc>>>0)<(2048);
-   if ($cmp2) {
-    $shr$28 = $wc >>> 6;
-    $or = $shr$28 | 192;
-    $conv5 = $or&255;
-    $incdec$ptr = ((($s)) + 1|0);
-    HEAP8[$s>>0] = $conv5;
-    $and = $wc & 63;
-    $or6 = $and | 128;
-    $conv7 = $or6&255;
-    HEAP8[$incdec$ptr>>0] = $conv7;
-    $retval$0 = 2;
-    break;
-   }
-   $cmp9 = ($wc>>>0)<(55296);
-   $0 = $wc & -8192;
-   $cmp11 = ($0|0)==(57344);
-   $or$cond = $cmp9 | $cmp11;
-   if ($or$cond) {
-    $shr14$26 = $wc >>> 12;
-    $or15 = $shr14$26 | 224;
-    $conv16 = $or15&255;
-    $incdec$ptr17 = ((($s)) + 1|0);
-    HEAP8[$s>>0] = $conv16;
-    $shr18$27 = $wc >>> 6;
-    $and19 = $shr18$27 & 63;
-    $or20 = $and19 | 128;
-    $conv21 = $or20&255;
-    $incdec$ptr22 = ((($s)) + 2|0);
-    HEAP8[$incdec$ptr17>>0] = $conv21;
-    $and23 = $wc & 63;
-    $or24 = $and23 | 128;
-    $conv25 = $or24&255;
-    HEAP8[$incdec$ptr22>>0] = $conv25;
-    $retval$0 = 3;
-    break;
-   }
-   $sub27 = (($wc) + -65536)|0;
-   $cmp28 = ($sub27>>>0)<(1048576);
-   if ($cmp28) {
-    $shr31$23 = $wc >>> 18;
-    $or32 = $shr31$23 | 240;
-    $conv33 = $or32&255;
-    $incdec$ptr34 = ((($s)) + 1|0);
-    HEAP8[$s>>0] = $conv33;
-    $shr35$24 = $wc >>> 12;
-    $and36 = $shr35$24 & 63;
-    $or37 = $and36 | 128;
-    $conv38 = $or37&255;
-    $incdec$ptr39 = ((($s)) + 2|0);
-    HEAP8[$incdec$ptr34>>0] = $conv38;
-    $shr40$25 = $wc >>> 6;
-    $and41 = $shr40$25 & 63;
-    $or42 = $and41 | 128;
-    $conv43 = $or42&255;
-    $incdec$ptr44 = ((($s)) + 3|0);
-    HEAP8[$incdec$ptr39>>0] = $conv43;
-    $and45 = $wc & 63;
-    $or46 = $and45 | 128;
-    $conv47 = $or46&255;
-    HEAP8[$incdec$ptr44>>0] = $conv47;
-    $retval$0 = 4;
-    break;
-   } else {
-    $call = (___errno_location()|0);
-    HEAP32[$call>>2] = 84;
-    $retval$0 = -1;
-    break;
-   }
-  }
- } while(0);
- return ($retval$0|0);
-}
-function _wctomb($s,$wc) {
- $s = $s|0;
- $wc = $wc|0;
- var $call = 0, $retval$0 = 0, $tobool = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $tobool = ($s|0)==(0|0);
- if ($tobool) {
-  $retval$0 = 0;
- } else {
-  $call = (_wcrtomb($s,$wc,0)|0);
-  $retval$0 = $call;
- }
- return ($retval$0|0);
-}
-function _memchr($src,$c,$n) {
- $src = $src|0;
- $c = $c|0;
- $n = $n|0;
- var $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0, $and = 0, $and$39 = 0, $and15 = 0, $and16 = 0, $cmp = 0, $cmp11 = 0, $cmp11$32 = 0, $cmp28 = 0, $cmp8 = 0, $cond = 0, $conv1 = 0, $dec = 0;
- var $dec34 = 0, $incdec$ptr = 0, $incdec$ptr21 = 0, $incdec$ptr33 = 0, $lnot = 0, $mul = 0, $n$addr$0$lcssa = 0, $n$addr$0$lcssa61 = 0, $n$addr$043 = 0, $n$addr$1$lcssa = 0, $n$addr$133 = 0, $n$addr$133$lcssa = 0, $n$addr$227 = 0, $n$addr$3 = 0, $neg = 0, $or$cond = 0, $or$cond$42 = 0, $s$0$lcssa = 0, $s$0$lcssa60 = 0, $s$044 = 0;
- var $s$128 = 0, $s$2 = 0, $sub = 0, $sub22 = 0, $tobool = 0, $tobool$40 = 0, $tobool2 = 0, $tobool2$41 = 0, $tobool2$lcssa = 0, $tobool25 = 0, $tobool25$26 = 0, $tobool36 = 0, $w$0$lcssa = 0, $w$034 = 0, $w$034$lcssa = 0, $xor = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $conv1 = $c & 255;
- $0 = $src;
- $and$39 = $0 & 3;
- $tobool$40 = ($and$39|0)!=(0);
- $tobool2$41 = ($n|0)!=(0);
- $or$cond$42 = $tobool2$41 & $tobool$40;
- L1: do {
-  if ($or$cond$42) {
-   $1 = $c&255;
-   $n$addr$043 = $n;$s$044 = $src;
-   while(1) {
-    $2 = HEAP8[$s$044>>0]|0;
-    $cmp = ($2<<24>>24)==($1<<24>>24);
-    if ($cmp) {
-     $n$addr$0$lcssa61 = $n$addr$043;$s$0$lcssa60 = $s$044;
-     label = 6;
-     break L1;
-    }
-    $incdec$ptr = ((($s$044)) + 1|0);
-    $dec = (($n$addr$043) + -1)|0;
-    $3 = $incdec$ptr;
-    $and = $3 & 3;
-    $tobool = ($and|0)!=(0);
-    $tobool2 = ($dec|0)!=(0);
-    $or$cond = $tobool2 & $tobool;
-    if ($or$cond) {
-     $n$addr$043 = $dec;$s$044 = $incdec$ptr;
-    } else {
-     $n$addr$0$lcssa = $dec;$s$0$lcssa = $incdec$ptr;$tobool2$lcssa = $tobool2;
-     label = 5;
-     break;
-    }
-   }
-  } else {
-   $n$addr$0$lcssa = $n;$s$0$lcssa = $src;$tobool2$lcssa = $tobool2$41;
-   label = 5;
-  }
- } while(0);
- if ((label|0) == 5) {
-  if ($tobool2$lcssa) {
-   $n$addr$0$lcssa61 = $n$addr$0$lcssa;$s$0$lcssa60 = $s$0$lcssa;
-   label = 6;
-  } else {
-   $n$addr$3 = 0;$s$2 = $s$0$lcssa;
-  }
- }
- L8: do {
-  if ((label|0) == 6) {
-   $4 = HEAP8[$s$0$lcssa60>>0]|0;
-   $5 = $c&255;
-   $cmp8 = ($4<<24>>24)==($5<<24>>24);
-   if ($cmp8) {
-    $n$addr$3 = $n$addr$0$lcssa61;$s$2 = $s$0$lcssa60;
-   } else {
-    $mul = Math_imul($conv1, 16843009)|0;
-    $cmp11$32 = ($n$addr$0$lcssa61>>>0)>(3);
-    L11: do {
-     if ($cmp11$32) {
-      $n$addr$133 = $n$addr$0$lcssa61;$w$034 = $s$0$lcssa60;
-      while(1) {
-       $6 = HEAP32[$w$034>>2]|0;
-       $xor = $6 ^ $mul;
-       $sub = (($xor) + -16843009)|0;
-       $neg = $xor & -2139062144;
-       $and15 = $neg ^ -2139062144;
-       $and16 = $and15 & $sub;
-       $lnot = ($and16|0)==(0);
-       if (!($lnot)) {
-        $n$addr$133$lcssa = $n$addr$133;$w$034$lcssa = $w$034;
-        break;
-       }
-       $incdec$ptr21 = ((($w$034)) + 4|0);
-       $sub22 = (($n$addr$133) + -4)|0;
-       $cmp11 = ($sub22>>>0)>(3);
-       if ($cmp11) {
-        $n$addr$133 = $sub22;$w$034 = $incdec$ptr21;
-       } else {
-        $n$addr$1$lcssa = $sub22;$w$0$lcssa = $incdec$ptr21;
-        label = 11;
-        break L11;
-       }
-      }
-      $n$addr$227 = $n$addr$133$lcssa;$s$128 = $w$034$lcssa;
-     } else {
-      $n$addr$1$lcssa = $n$addr$0$lcssa61;$w$0$lcssa = $s$0$lcssa60;
-      label = 11;
-     }
-    } while(0);
-    if ((label|0) == 11) {
-     $tobool25$26 = ($n$addr$1$lcssa|0)==(0);
-     if ($tobool25$26) {
-      $n$addr$3 = 0;$s$2 = $w$0$lcssa;
-      break;
-     } else {
-      $n$addr$227 = $n$addr$1$lcssa;$s$128 = $w$0$lcssa;
-     }
-    }
-    while(1) {
-     $7 = HEAP8[$s$128>>0]|0;
-     $cmp28 = ($7<<24>>24)==($5<<24>>24);
-     if ($cmp28) {
-      $n$addr$3 = $n$addr$227;$s$2 = $s$128;
-      break L8;
-     }
-     $incdec$ptr33 = ((($s$128)) + 1|0);
-     $dec34 = (($n$addr$227) + -1)|0;
-     $tobool25 = ($dec34|0)==(0);
-     if ($tobool25) {
-      $n$addr$3 = 0;$s$2 = $incdec$ptr33;
-      break;
-     } else {
-      $n$addr$227 = $dec34;$s$128 = $incdec$ptr33;
-     }
-    }
-   }
-  }
- } while(0);
- $tobool36 = ($n$addr$3|0)!=(0);
- $cond = $tobool36 ? $s$2 : 0;
- return ($cond|0);
-}
-function ___syscall_ret($r) {
- $r = $r|0;
- var $call = 0, $cmp = 0, $retval$0 = 0, $sub = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $cmp = ($r>>>0)>(4294963200);
- if ($cmp) {
-  $sub = (0 - ($r))|0;
-  $call = (___errno_location()|0);
-  HEAP32[$call>>2] = $sub;
-  $retval$0 = -1;
- } else {
-  $retval$0 = $r;
- }
- return ($retval$0|0);
-}
-function ___fflush_unlocked($f) {
- $f = $f|0;
- var $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $cmp = 0, $cmp4 = 0, $rend = 0, $retval$0 = 0, $rpos = 0, $seek = 0, $sub$ptr$lhs$cast = 0, $sub$ptr$rhs$cast = 0, $sub$ptr$sub = 0, $tobool = 0, $wbase = 0, $wend = 0, $wpos = 0;
- var $write = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $wpos = ((($f)) + 20|0);
- $0 = HEAP32[$wpos>>2]|0;
- $wbase = ((($f)) + 28|0);
- $1 = HEAP32[$wbase>>2]|0;
- $cmp = ($0>>>0)>($1>>>0);
- if ($cmp) {
-  $write = ((($f)) + 36|0);
-  $2 = HEAP32[$write>>2]|0;
-  (FUNCTION_TABLE_iiii[$2 & 7]($f,0,0)|0);
-  $3 = HEAP32[$wpos>>2]|0;
-  $tobool = ($3|0)==(0|0);
-  if ($tobool) {
-   $retval$0 = -1;
-  } else {
-   label = 3;
-  }
- } else {
-  label = 3;
- }
- if ((label|0) == 3) {
-  $rpos = ((($f)) + 4|0);
-  $4 = HEAP32[$rpos>>2]|0;
-  $rend = ((($f)) + 8|0);
-  $5 = HEAP32[$rend>>2]|0;
-  $cmp4 = ($4>>>0)<($5>>>0);
-  if ($cmp4) {
-   $seek = ((($f)) + 40|0);
-   $6 = HEAP32[$seek>>2]|0;
-   $sub$ptr$lhs$cast = $4;
-   $sub$ptr$rhs$cast = $5;
-   $sub$ptr$sub = (($sub$ptr$lhs$cast) - ($sub$ptr$rhs$cast))|0;
-   (FUNCTION_TABLE_iiii[$6 & 7]($f,$sub$ptr$sub,1)|0);
-  }
-  $wend = ((($f)) + 16|0);
-  HEAP32[$wend>>2] = 0;
-  HEAP32[$wbase>>2] = 0;
-  HEAP32[$wpos>>2] = 0;
-  HEAP32[$rend>>2] = 0;
-  HEAP32[$rpos>>2] = 0;
-  $retval$0 = 0;
- }
- return ($retval$0|0);
-}
-function _cleanup($p) {
- $p = $p|0;
- var $0 = 0, $lockcount = 0, $tobool = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $lockcount = ((($p)) + 68|0);
- $0 = HEAP32[$lockcount>>2]|0;
- $tobool = ($0|0)==(0);
- if ($tobool) {
-  ___unlockfile($p);
- }
- return;
-}
-function _printf_core($f,$fmt,$ap,$nl_arg,$nl_type) {
- $f = $f|0;
- $fmt = $fmt|0;
- $ap = $ap|0;
- $nl_arg = $nl_arg|0;
- $nl_type = $nl_type|0;
- var $$ = 0, $$$i = 0, $$396$i = 0.0, $$404$i = 0.0, $$l10n$0 = 0, $$lcssa = 0, $$p$i = 0, $$p$inc468$i = 0, $$pr$i = 0, $$pr477$i = 0, $$pre = 0, $$pre$i = 0, $$pre357 = 0, $$pre564$i = 0, $$pre566$i = 0, $$pre567$i = 0, $$sub514$i = 0, $$sub562$i = 0, $0 = 0, $1 = 0;
- var $10 = 0, $100 = 0, $101 = 0, $102 = 0, $103 = 0, $104 = 0, $105 = 0, $106 = 0, $107 = 0, $108 = 0, $109 = 0, $11 = 0, $110 = 0, $111 = 0, $112 = 0, $113 = 0, $114 = 0, $115 = 0, $116 = 0, $117 = 0;
- var $118 = 0, $119 = 0, $12 = 0, $120 = 0, $121 = 0, $122 = 0, $123 = 0, $124 = 0, $125 = 0, $126 = 0, $127 = 0, $128 = 0, $129 = 0, $13 = 0, $130 = 0, $131 = 0, $132 = 0, $133 = 0, $134 = 0, $135 = 0;
- var $136 = 0, $137 = 0, $138 = 0, $139 = 0, $14 = 0, $140 = 0, $141 = 0, $142 = 0, $143 = 0, $144 = 0, $145 = 0, $146 = 0, $147 = 0, $148 = 0, $149 = 0, $15 = 0, $150 = 0, $151 = 0, $152 = 0, $153 = 0;
- var $154 = 0, $155 = 0, $156 = 0, $157 = 0, $158 = 0, $159 = 0, $16 = 0, $160 = 0, $161 = 0, $162 = 0, $163 = 0, $164 = 0, $165 = 0, $166 = 0, $167 = 0, $168 = 0, $169 = 0, $17 = 0, $170 = 0, $171 = 0;
- var $172 = 0, $173 = 0, $174 = 0, $175 = 0, $176 = 0, $177 = 0, $178 = 0, $179 = 0, $18 = 0, $180 = 0, $181 = 0.0, $182 = 0, $183 = 0, $184 = 0, $185 = 0, $186 = 0, $187 = 0, $188 = 0, $189 = 0, $19 = 0;
- var $190 = 0, $191 = 0, $192 = 0, $193 = 0, $194 = 0, $195 = 0, $196 = 0, $197 = 0, $198 = 0, $199 = 0, $2 = 0, $20 = 0, $200 = 0, $201 = 0, $202 = 0, $203 = 0, $204 = 0, $205 = 0, $206 = 0, $207 = 0;
- var $208 = 0, $209 = 0, $21 = 0, $210 = 0, $211 = 0, $212 = 0, $213 = 0, $214 = 0, $215 = 0, $216 = 0, $217 = 0, $218 = 0, $219 = 0, $22 = 0, $220 = 0, $221 = 0, $222 = 0, $223 = 0, $224 = 0, $225 = 0;
- var $226 = 0, $227 = 0, $228 = 0, $229 = 0, $23 = 0, $230 = 0, $231 = 0, $232 = 0, $233 = 0, $234 = 0, $235 = 0, $236 = 0, $237 = 0, $238 = 0, $239 = 0, $24 = 0, $240 = 0, $241 = 0, $242 = 0, $243 = 0;
- var $244 = 0, $245 = 0, $246 = 0, $247 = 0, $248 = 0, $249 = 0, $25 = 0, $250 = 0, $251 = 0, $252 = 0, $253 = 0, $254 = 0, $255 = 0, $256 = 0, $257 = 0, $258 = 0, $259 = 0, $26 = 0, $260 = 0, $261 = 0;
- var $262 = 0, $263 = 0, $264 = 0, $265 = 0, $266 = 0, $267 = 0, $268 = 0, $27 = 0, $28 = 0, $29 = 0, $3 = 0, $30 = 0, $31 = 0, $32 = 0, $33 = 0, $34 = 0, $35 = 0, $36 = 0, $37 = 0, $38 = 0;
- var $39 = 0, $4 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, $49 = 0, $5 = 0, $50 = 0, $51 = 0, $52 = 0, $53 = 0, $54 = 0, $55 = 0, $56 = 0;
- var $57 = 0, $58 = 0, $59 = 0, $6 = 0, $60 = 0, $61 = 0, $62 = 0, $63 = 0, $64 = 0, $65 = 0, $66 = 0, $67 = 0, $68 = 0, $69 = 0, $7 = 0, $70 = 0, $71 = 0, $72 = 0, $73 = 0, $74 = 0;
- var $75 = 0, $76 = 0, $77 = 0, $78 = 0, $79 = 0, $8 = 0, $80 = 0, $81 = 0, $82 = 0, $83 = 0, $84 = 0, $85 = 0, $86 = 0, $87 = 0, $88 = 0, $89 = 0, $9 = 0, $90 = 0, $91 = 0, $92 = 0;
- var $93 = 0, $94 = 0, $95 = 0, $96 = 0, $97 = 0, $98 = 0, $99 = 0, $a$0 = 0, $a$1 = 0, $a$1$lcssa$i = 0, $a$1549$i = 0, $a$2 = 0, $a$2$ph$i = 0, $a$3$lcssa$i = 0, $a$3539$i = 0, $a$5$lcssa$i = 0, $a$5521$i = 0, $a$6$i = 0, $a$8$i = 0, $a$9$ph$i = 0;
- var $add = 0, $add$i = 0, $add$i$203 = 0, $add$i$239 = 0, $add$i$lcssa = 0, $add$ptr = 0, $add$ptr139 = 0, $add$ptr205 = 0, $add$ptr213$i = 0, $add$ptr257 = 0, $add$ptr311$i = 0, $add$ptr311$z$4$i = 0, $add$ptr340 = 0, $add$ptr354$i = 0, $add$ptr358$i = 0, $add$ptr359 = 0, $add$ptr373$i = 0, $add$ptr43 = 0, $add$ptr43$arrayidx31 = 0, $add$ptr442$i = 0;
- var $add$ptr442$z$3$i = 0, $add$ptr473 = 0, $add$ptr65$i = 0, $add$ptr671$i = 0, $add$ptr742$i = 0, $add$ptr88 = 0, $add113$i = 0, $add150$i = 0, $add154$i = 0, $add163$i = 0, $add165$i = 0, $add269 = 0, $add269$p$0 = 0, $add273$i = 0, $add275$i = 0, $add284$i = 0, $add313$i = 0, $add322 = 0, $add355$i = 0, $add395 = 0;
- var $add410$i = 0.0, $add412 = 0, $add414$i = 0, $add441 = 0, $add477$neg$i = 0, $add561$i = 0, $add608$i = 0, $add612$i = 0, $add620$i = 0, $add653$i = 0, $add67$i = 0, $add737$i = 0, $add810$i = 0, $add87$i = 0.0, $add90$i = 0.0, $and = 0, $and$i = 0, $and$i$216 = 0, $and$i$231 = 0, $and$i$238 = 0;
- var $and$i$244 = 0, $and$i$406$i = 0, $and$i$412$i = 0, $and$i$418$i = 0, $and$i$424$i = 0, $and$i$430$i = 0, $and$i$436$i = 0, $and$i$442$i = 0, $and$i$448$i = 0, $and$i$454$i = 0, $and$i$460$i = 0, $and$i$466$i = 0, $and$i$472$i = 0, $and$i$i = 0, $and12$i = 0, $and134$i = 0, $and210 = 0, $and214 = 0, $and216 = 0, $and219 = 0;
- var $and249 = 0, $and254 = 0, $and263 = 0, $and282$i = 0, $and289 = 0, $and294 = 0, $and309 = 0, $and309$fl$4 = 0, $and36$i = 0, $and379$i = 0, $and483$i = 0, $and610$pre$phi$iZ2D = 0, $and62$i = 0, $arg = 0, $arglist_current = 0, $arglist_current2 = 0, $arglist_next = 0, $arglist_next3 = 0, $argpos$0 = 0, $arraydecay208$add$ptr213$i = 0;
- var $arrayidx$i = 0, $arrayidx$i$236 = 0, $arrayidx114 = 0, $arrayidx117$i = 0, $arrayidx119 = 0, $arrayidx124 = 0, $arrayidx132 = 0, $arrayidx16 = 0, $arrayidx173 = 0, $arrayidx192 = 0, $arrayidx251$i = 0, $arrayidx31 = 0, $arrayidx35 = 0, $arrayidx370 = 0, $arrayidx453$i = 0, $arrayidx469 = 0, $arrayidx481 = 0, $arrayidx489$i = 0, $arrayidx68 = 0, $arrayidx73 = 0;
- var $arrayidx81 = 0, $big$i = 0, $buf = 0, $buf$i = 0, $call = 0, $call344 = 0, $call345 = 0, $call356 = 0, $call384 = 0, $call411 = 0, $call55$i = 0.0, $carry$0544$i = 0, $carry262$0535$i = 0, $cmp = 0, $cmp1 = 0, $cmp103$i = 0, $cmp105 = 0, $cmp111 = 0, $cmp116 = 0, $cmp126 = 0;
- var $cmp127$i = 0, $cmp13 = 0, $cmp147$i = 0, $cmp165 = 0, $cmp176 = 0, $cmp18 = 0, $cmp181 = 0, $cmp184 = 0, $cmp188$i = 0, $cmp196$i = 0, $cmp205$i = 0, $cmp211 = 0, $cmp225$547$i = 0, $cmp225$i = 0, $cmp228$i = 0, $cmp235$543$i = 0, $cmp235$i = 0, $cmp240 = 0, $cmp249$i = 0, $cmp259$537$i = 0;
- var $cmp259$i = 0, $cmp265$i = 0, $cmp270 = 0, $cmp277$533$i = 0, $cmp277$i = 0, $cmp299$i = 0, $cmp306 = 0, $cmp308$i = 0, $cmp315$i = 0, $cmp323 = 0, $cmp324$529$i = 0, $cmp324$i = 0, $cmp333$i = 0, $cmp338$i = 0, $cmp350$i = 0, $cmp363$525$i = 0, $cmp37 = 0, $cmp374$i = 0, $cmp377 = 0, $cmp377$314 = 0;
- var $cmp38$i = 0, $cmp385 = 0, $cmp385$i = 0, $cmp390 = 0, $cmp390$i = 0, $cmp397 = 0, $cmp403$i = 0, $cmp404 = 0, $cmp404$324 = 0, $cmp411$i = 0, $cmp413 = 0, $cmp416$519$i = 0, $cmp416$i = 0, $cmp420$i = 0, $cmp421 = 0, $cmp433$515$i = 0, $cmp433$i = 0, $cmp434 = 0, $cmp442 = 0, $cmp443$i = 0;
- var $cmp450$i = 0, $cmp450$lcssa$i = 0, $cmp466 = 0, $cmp470$i = 0, $cmp473$i = 0, $cmp478 = 0, $cmp478$295 = 0, $cmp48$i = 0, $cmp495$511$i = 0, $cmp495$i = 0, $cmp50 = 0, $cmp50$308 = 0, $cmp505$i = 0, $cmp515$i = 0, $cmp528$i = 0, $cmp563$i = 0, $cmp577$i = 0, $cmp59$i = 0, $cmp614$i = 0, $cmp617$i = 0;
- var $cmp623$i = 0, $cmp636$506$i = 0, $cmp636$i = 0, $cmp65 = 0, $cmp660$i = 0, $cmp665$i = 0, $cmp673$i = 0, $cmp678$491$i = 0, $cmp678$i = 0, $cmp686$i = 0, $cmp707$486$i = 0, $cmp707$i = 0, $cmp710$487$i = 0, $cmp710$i = 0, $cmp722$483$i = 0, $cmp722$i = 0, $cmp727$i = 0, $cmp745$i = 0, $cmp748$499$i = 0, $cmp748$i = 0;
- var $cmp75 = 0, $cmp760$i = 0, $cmp765$i = 0, $cmp770$495$i = 0, $cmp770$i = 0, $cmp777$i = 0, $cmp790$i = 0, $cmp818$i = 0, $cmp82$i = 0, $cmp94$i = 0, $cmp97 = 0, $cnt$0 = 0, $cnt$1 = 0, $cnt$1$lcssa = 0, $cond$i = 0, $cond100$i = 0, $cond233$i = 0, $cond245 = 0, $cond271$i = 0, $cond304$i = 0;
- var $cond354 = 0, $cond426 = 0, $cond43$i = 0, $cond53$i = 0, $cond629$i = 0, $cond732$i = 0, $cond800$i = 0, $conv$4$i = 0, $conv$4$i$197 = 0, $conv$4$i$211 = 0, $conv$i = 0, $conv$i$205 = 0, $conv1$i = 0, $conv111$i = 0, $conv114$i = 0, $conv116$i = 0, $conv118$393$i = 0, $conv120 = 0, $conv121$i = 0, $conv123$i = 0.0;
- var $conv134 = 0, $conv163 = 0, $conv174 = 0, $conv174$lcssa = 0, $conv207 = 0, $conv216$i = 0, $conv218$i = 0.0, $conv229 = 0, $conv232 = 0, $conv242$i$lcssa = 0, $conv32 = 0, $conv48 = 0, $conv48$307 = 0, $conv48311 = 0, $conv58 = 0, $conv644$i = 0, $conv646$i = 0, $conv69 = 0, $conv83 = 0, $d$0$542$i = 0;
- var $d$0$i = 0, $d$0545$i = 0, $d$1534$i = 0, $d$2$lcssa$i = 0, $d$2520$i = 0, $d$4$i = 0, $d$5494$i = 0, $d$6488$i = 0, $d$7500$i = 0, $dec$i = 0, $dec476$i = 0, $dec481$i = 0, $dec78$i = 0, $div274$i = 0, $div356$i = 0, $div378$i = 0, $div384$i = 0, $e$0531$i = 0, $e$1$i = 0, $e$2517$i = 0;
- var $e$4$i = 0, $e$5$ph$i = 0, $e2$i = 0, $ebuf0$i = 0, $estr$0$i = 0, $estr$1$lcssa$i = 0, $estr$1507$i = 0, $estr$2$i = 0, $exitcond$i = 0, $expanded = 0, $expanded10 = 0, $expanded11 = 0, $expanded13 = 0, $expanded14 = 0, $expanded15 = 0, $expanded4 = 0, $expanded6 = 0, $expanded7 = 0, $expanded8 = 0, $fl$0284 = 0;
- var $fl$0310 = 0, $fl$1 = 0, $fl$1$and219 = 0, $fl$3 = 0, $fl$4 = 0, $fl$6 = 0, $i$0$lcssa = 0, $i$0$lcssa368 = 0, $i$0316 = 0, $i$0530$i = 0, $i$07$i = 0, $i$07$i$201 = 0, $i$1$lcssa$i = 0, $i$1325 = 0, $i$1526$i = 0, $i$2299 = 0, $i$2299$lcssa = 0, $i$2516$i = 0, $i$3296 = 0, $i$3512$i = 0;
- var $i137 = 0, $i86 = 0, $idxprom$i = 0, $inc = 0, $inc$i = 0, $inc425$i = 0, $inc438$i = 0, $inc468$i = 0, $inc488 = 0, $inc500$i = 0, $incdec$ptr = 0, $incdec$ptr$i = 0, $incdec$ptr$i$204 = 0, $incdec$ptr$i$212 = 0, $incdec$ptr$i$212$lcssa = 0, $incdec$ptr$i$225 = 0, $incdec$ptr$i$lcssa = 0, $incdec$ptr106$i = 0, $incdec$ptr112$i = 0, $incdec$ptr115$i = 0;
- var $incdec$ptr122$i = 0, $incdec$ptr137$i = 0, $incdec$ptr169 = 0, $incdec$ptr169$lcssa = 0, $incdec$ptr169269 = 0, $incdec$ptr169271 = 0, $incdec$ptr169271$lcssa414 = 0, $incdec$ptr169272 = 0, $incdec$ptr169274 = 0, $incdec$ptr169275 = 0, $incdec$ptr169276$lcssa = 0, $incdec$ptr169276301 = 0, $incdec$ptr217$i = 0, $incdec$ptr217$i$lcssa = 0, $incdec$ptr23 = 0, $incdec$ptr246$i = 0, $incdec$ptr288$i = 0, $incdec$ptr292$570$i = 0, $incdec$ptr292$a$3$571$i = 0, $incdec$ptr292$a$3$i = 0;
- var $incdec$ptr292$a$3573$i = 0, $incdec$ptr292$i = 0, $incdec$ptr296$i = 0, $incdec$ptr383 = 0, $incdec$ptr410 = 0, $incdec$ptr419$i = 0, $incdec$ptr423$i = 0, $incdec$ptr62 = 0, $incdec$ptr639$i = 0, $incdec$ptr645$i = 0, $incdec$ptr647$i = 0, $incdec$ptr681$i = 0, $incdec$ptr689$i = 0, $incdec$ptr698$i = 0, $incdec$ptr698$i$lcssa = 0, $incdec$ptr725$i = 0, $incdec$ptr734$i = 0, $incdec$ptr773$i = 0, $incdec$ptr776$i = 0, $incdec$ptr808$i = 0;
- var $isdigit = 0, $isdigit$6$i = 0, $isdigit$6$i$199 = 0, $isdigit$i = 0, $isdigit$i$207 = 0, $isdigit188 = 0, $isdigit190 = 0, $isdigittmp = 0, $isdigittmp$ = 0, $isdigittmp$5$i = 0, $isdigittmp$5$i$198 = 0, $isdigittmp$i = 0, $isdigittmp$i$206 = 0, $isdigittmp187 = 0, $isdigittmp189 = 0, $isdigittmp8$i = 0, $isdigittmp8$i$200 = 0, $j$0$524$i = 0, $j$0$i = 0, $j$0527$i = 0;
- var $j$1513$i = 0, $j$2$i = 0, $l$0 = 0, $l$0$i = 0, $l$1$i = 0, $l$1315 = 0, $l$2 = 0, $l10n$0 = 0, $l10n$0$lcssa = 0, $l10n$0$phi = 0, $l10n$1 = 0, $l10n$2 = 0, $l10n$3 = 0, $land$ext$neg$i = 0, $lnot$ext = 0, $lnot$i = 0, $lnot455$i = 0, $lnot483 = 0, $lor$ext$i = 0, $mb = 0;
- var $mul$i = 0, $mul$i$202 = 0, $mul$i$240 = 0.0, $mul125$i = 0.0, $mul202$i = 0.0, $mul220$i = 0.0, $mul286$i = 0, $mul286$i$lcssa = 0, $mul322$i = 0, $mul328$i = 0, $mul335$i = 0, $mul349$i = 0, $mul367$i = 0, $mul406$i = 0.0, $mul407$i = 0.0, $mul431$i = 0, $mul437$i = 0, $mul499$i = 0, $mul513$i = 0, $mul80$i = 0.0;
- var $mul80$i$lcssa = 0.0, $notlhs$i = 0, $notrhs$i = 0, $or = 0, $or$cond = 0, $or$cond$i = 0, $or$cond1$not$i = 0, $or$cond192 = 0, $or$cond193 = 0, $or$cond195 = 0, $or$cond2$i = 0, $or$cond384 = 0, $or$cond395$i = 0, $or$cond397$i = 0, $or$cond401$i = 0, $or$i = 0, $or$i$241 = 0, $or100 = 0, $or120$i = 0, $or246 = 0;
- var $or504$i = 0, $or613$i = 0, $p$0 = 0, $p$1 = 0, $p$2 = 0, $p$2$add322 = 0, $p$3 = 0, $p$4365 = 0, $p$5 = 0, $p$addr$2$$sub514398$i = 0, $p$addr$2$$sub562399$i = 0, $p$addr$2$i = 0, $p$addr$3$i = 0, $p$addr$4$lcssa$i = 0, $p$addr$4489$i = 0, $p$addr$5$lcssa$i = 0, $p$addr$5501$i = 0, $pl$0 = 0, $pl$0$i = 0, $pl$1 = 0;
- var $pl$1$i = 0, $pl$2 = 0, $prefix$0 = 0, $prefix$0$add$ptr65$i = 0, $prefix$0$i = 0, $prefix$1 = 0, $prefix$2 = 0, $r$0$a$9$i = 0, $re$1482$i = 0, $rem360$i = 0, $rem370$i = 0, $rem494$510$i = 0, $rem494$i = 0, $retval$0 = 0, $retval$0$i = 0, $round$0481$i = 0.0, $round377$1$i = 0.0, $s$0$i = 0, $s$1$i = 0, $s$1$i$lcssa = 0;
- var $s$addr$0$lcssa$i$229 = 0, $s$addr$06$i = 0, $s$addr$06$i$221 = 0, $s35$0$i = 0, $s668$0492$i = 0, $s668$1$i = 0, $s715$0$lcssa$i = 0, $s715$0484$i = 0, $s753$0$i = 0, $s753$1496$i = 0, $s753$2$i = 0, $shl = 0, $shl280$i = 0, $shl60 = 0, $shr = 0, $shr283$i = 0, $shr285$i = 0, $small$0$i = 0.0, $small$1$i = 0.0, $st$0 = 0;
- var $st$0$lcssa415 = 0, $storemerge = 0, $storemerge$186282 = 0, $storemerge$186309 = 0, $storemerge$191 = 0, $sub = 0, $sub$i = 0.0, $sub$ptr$div$i = 0, $sub$ptr$div321$i = 0, $sub$ptr$div347$i = 0, $sub$ptr$div430$i = 0, $sub$ptr$div511$i = 0, $sub$ptr$lhs$cast = 0, $sub$ptr$lhs$cast$i = 0, $sub$ptr$lhs$cast160$i = 0, $sub$ptr$lhs$cast305$i = 0, $sub$ptr$lhs$cast317 = 0, $sub$ptr$lhs$cast344$i = 0, $sub$ptr$lhs$cast361 = 0, $sub$ptr$lhs$cast431 = 0;
- var $sub$ptr$lhs$cast508$i = 0, $sub$ptr$lhs$cast694$i = 0, $sub$ptr$rhs$cast = 0, $sub$ptr$rhs$cast$i = 0, $sub$ptr$rhs$cast152$i = 0, $sub$ptr$rhs$cast161$i = 0, $sub$ptr$rhs$cast174$i = 0, $sub$ptr$rhs$cast267 = 0, $sub$ptr$rhs$cast306$i = 0, $sub$ptr$rhs$cast318 = 0, $sub$ptr$rhs$cast319$i = 0, $sub$ptr$rhs$cast345$i = 0, $sub$ptr$rhs$cast362 = 0, $sub$ptr$rhs$cast428$i = 0, $sub$ptr$rhs$cast432 = 0, $sub$ptr$rhs$cast634$504$i = 0, $sub$ptr$rhs$cast634$i = 0, $sub$ptr$rhs$cast649$i = 0, $sub$ptr$rhs$cast695$i = 0, $sub$ptr$rhs$cast788$i = 0;
- var $sub$ptr$rhs$cast812$i = 0, $sub$ptr$sub = 0, $sub$ptr$sub$i = 0, $sub$ptr$sub145$i = 0, $sub$ptr$sub153$i = 0, $sub$ptr$sub159$i = 0, $sub$ptr$sub162$i = 0, $sub$ptr$sub172$i = 0, $sub$ptr$sub175$i = 0, $sub$ptr$sub268 = 0, $sub$ptr$sub307$i = 0, $sub$ptr$sub319 = 0, $sub$ptr$sub320$i = 0, $sub$ptr$sub346$i = 0, $sub$ptr$sub363 = 0, $sub$ptr$sub429$i = 0, $sub$ptr$sub433 = 0, $sub$ptr$sub433$p$5 = 0, $sub$ptr$sub510$i = 0, $sub$ptr$sub635$505$i = 0;
- var $sub$ptr$sub635$i = 0, $sub$ptr$sub650$i = 0, $sub$ptr$sub650$pn$i = 0, $sub$ptr$sub696$i = 0, $sub$ptr$sub789$i = 0, $sub$ptr$sub813$i = 0, $sub101 = 0, $sub124$i = 0.0, $sub135 = 0, $sub146$i = 0, $sub164 = 0, $sub175 = 0, $sub181$i = 0, $sub203$i = 0, $sub219$i = 0.0, $sub256$i = 0, $sub264$i = 0, $sub281$i = 0, $sub336$i = 0, $sub343$i = 0;
- var $sub357$i = 0, $sub389 = 0, $sub409$i = 0, $sub478$i = 0, $sub480$i = 0, $sub514$i = 0, $sub54 = 0, $sub562$i = 0, $sub59 = 0, $sub626$le$i = 0, $sub735$i = 0, $sub74$i = 0, $sub806$i = 0, $sub84 = 0, $sub85$i = 0.0, $sub86$i = 0.0, $sub88$i = 0.0, $sub91$i = 0.0, $sub97$i = 0, $sum = 0;
- var $t$0 = 0, $t$1 = 0, $t$addr$0$i = 0, $t$addr$1$i = 0, $tobool = 0, $tobool$i = 0, $tobool$i$217 = 0, $tobool$i$232 = 0, $tobool$i$245 = 0, $tobool$i$407$i = 0, $tobool$i$413$i = 0, $tobool$i$419$i = 0, $tobool$i$425$i = 0, $tobool$i$431$i = 0, $tobool$i$437$i = 0, $tobool$i$443$i = 0, $tobool$i$449$i = 0, $tobool$i$455$i = 0, $tobool$i$461$i = 0, $tobool$i$467$i = 0;
- var $tobool$i$473$i = 0, $tobool$i$i = 0, $tobool13$i = 0, $tobool135$i = 0, $tobool139$i = 0, $tobool140$i = 0, $tobool141 = 0, $tobool178 = 0, $tobool208 = 0, $tobool217 = 0, $tobool222$i = 0, $tobool244$i = 0, $tobool25 = 0, $tobool255 = 0, $tobool264 = 0, $tobool28 = 0, $tobool290 = 0, $tobool290$569$i = 0, $tobool290$i = 0, $tobool294$i = 0;
- var $tobool295 = 0, $tobool314 = 0, $tobool341$i = 0, $tobool349 = 0, $tobool357 = 0, $tobool37$i = 0, $tobool371$i = 0, $tobool380 = 0, $tobool380$i = 0, $tobool400$i = 0, $tobool407 = 0, $tobool459 = 0, $tobool462 = 0, $tobool470 = 0, $tobool484$i = 0, $tobool490$i = 0, $tobool55 = 0, $tobool56$i = 0, $tobool63$i = 0, $tobool76$i = 0;
- var $tobool76552$i = 0, $tobool781$i = 0, $tobool79$i = 0, $tobool9$i = 0, $tobool90 = 0, $w$0 = 0, $w$1 = 0, $w$2 = 0, $w$add165$i = 0, $w$add653$i = 0, $wc = 0, $ws$0317 = 0, $ws$1326 = 0, $xor = 0, $xor$i = 0, $xor167$i = 0, $xor186$i = 0, $xor449 = 0, $xor457 = 0, $xor655$i = 0;
- var $xor816$i = 0, $y$addr$0$i = 0.0, $y$addr$1$i = 0.0, $y$addr$2$i = 0.0, $y$addr$3$i = 0.0, $y$addr$4$i = 0.0, $z$0$i = 0, $z$0$lcssa = 0, $z$0302 = 0, $z$1 = 0, $z$1$lcssa$i = 0, $z$1548$i = 0, $z$2 = 0, $z$2$i = 0, $z$2$i$lcssa = 0, $z$3$lcssa$i = 0, $z$3538$i = 0, $z$4$i = 0, $z$7$add$ptr742$i = 0, $z$7$i = 0;
- var $z$7$i$lcssa = 0, $z$7$ph$i = 0, label = 0, sp = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 624|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
- $big$i = sp + 24|0;
- $e2$i = sp + 16|0;
- $buf$i = sp + 588|0;
- $ebuf0$i = sp + 576|0;
- $arg = sp;
- $buf = sp + 536|0;
- $wc = sp + 8|0;
- $mb = sp + 528|0;
- $tobool25 = ($f|0)!=(0|0);
- $add$ptr205 = ((($buf)) + 40|0);
- $sub$ptr$lhs$cast317 = $add$ptr205;
- $add$ptr340 = ((($buf)) + 39|0);
- $arrayidx370 = ((($wc)) + 4|0);
- $arrayidx$i$236 = ((($ebuf0$i)) + 12|0);
- $incdec$ptr106$i = ((($ebuf0$i)) + 11|0);
- $sub$ptr$rhs$cast$i = $buf$i;
- $sub$ptr$lhs$cast160$i = $arrayidx$i$236;
- $sub$ptr$sub159$i = (($sub$ptr$lhs$cast160$i) - ($sub$ptr$rhs$cast$i))|0;
- $sub$ptr$sub145$i = (-2 - ($sub$ptr$rhs$cast$i))|0;
- $sub$ptr$sub153$i = (($sub$ptr$lhs$cast160$i) + 2)|0;
- $add$ptr213$i = ((($big$i)) + 288|0);
- $add$ptr671$i = ((($buf$i)) + 9|0);
- $sub$ptr$lhs$cast694$i = $add$ptr671$i;
- $incdec$ptr689$i = ((($buf$i)) + 8|0);
- $cnt$0 = 0;$incdec$ptr169275 = $fmt;$l$0 = 0;$l10n$0 = 0;
- L1: while(1) {
-  $cmp = ($cnt$0|0)>(-1);
-  do {
-   if ($cmp) {
-    $sub = (2147483647 - ($cnt$0))|0;
-    $cmp1 = ($l$0|0)>($sub|0);
-    if ($cmp1) {
-     $call = (___errno_location()|0);
-     HEAP32[$call>>2] = 75;
-     $cnt$1 = -1;
-     break;
-    } else {
-     $add = (($l$0) + ($cnt$0))|0;
-     $cnt$1 = $add;
-     break;
-    }
-   } else {
-    $cnt$1 = $cnt$0;
-   }
-  } while(0);
-  $0 = HEAP8[$incdec$ptr169275>>0]|0;
-  $tobool = ($0<<24>>24)==(0);
-  if ($tobool) {
-   $cnt$1$lcssa = $cnt$1;$l10n$0$lcssa = $l10n$0;
-   label = 242;
-   break;
-  } else {
-   $1 = $0;$incdec$ptr169274 = $incdec$ptr169275;
-  }
-  L9: while(1) {
-   switch ($1<<24>>24) {
-   case 37:  {
-    $incdec$ptr169276301 = $incdec$ptr169274;$z$0302 = $incdec$ptr169274;
-    label = 9;
-    break L9;
-    break;
-   }
-   case 0:  {
-    $incdec$ptr169276$lcssa = $incdec$ptr169274;$z$0$lcssa = $incdec$ptr169274;
-    break L9;
-    break;
-   }
-   default: {
-   }
-   }
-   $incdec$ptr = ((($incdec$ptr169274)) + 1|0);
-   $$pre = HEAP8[$incdec$ptr>>0]|0;
-   $1 = $$pre;$incdec$ptr169274 = $incdec$ptr;
-  }
-  L12: do {
-   if ((label|0) == 9) {
-    while(1) {
-     label = 0;
-     $arrayidx16 = ((($incdec$ptr169276301)) + 1|0);
-     $2 = HEAP8[$arrayidx16>>0]|0;
-     $cmp18 = ($2<<24>>24)==(37);
-     if (!($cmp18)) {
-      $incdec$ptr169276$lcssa = $incdec$ptr169276301;$z$0$lcssa = $z$0302;
-      break L12;
-     }
-     $incdec$ptr23 = ((($z$0302)) + 1|0);
-     $add$ptr = ((($incdec$ptr169276301)) + 2|0);
-     $3 = HEAP8[$add$ptr>>0]|0;
-     $cmp13 = ($3<<24>>24)==(37);
-     if ($cmp13) {
-      $incdec$ptr169276301 = $add$ptr;$z$0302 = $incdec$ptr23;
-      label = 9;
-     } else {
-      $incdec$ptr169276$lcssa = $add$ptr;$z$0$lcssa = $incdec$ptr23;
-      break;
-     }
-    }
-   }
-  } while(0);
-  $sub$ptr$lhs$cast = $z$0$lcssa;
-  $sub$ptr$rhs$cast = $incdec$ptr169275;
-  $sub$ptr$sub = (($sub$ptr$lhs$cast) - ($sub$ptr$rhs$cast))|0;
-  if ($tobool25) {
-   $4 = HEAP32[$f>>2]|0;
-   $and$i = $4 & 32;
-   $tobool$i = ($and$i|0)==(0);
-   if ($tobool$i) {
-    (___fwritex($incdec$ptr169275,$sub$ptr$sub,$f)|0);
-   }
-  }
-  $tobool28 = ($z$0$lcssa|0)==($incdec$ptr169275|0);
-  if (!($tobool28)) {
-   $l10n$0$phi = $l10n$0;$cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169276$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$0$phi;
-   continue;
-  }
-  $arrayidx31 = ((($incdec$ptr169276$lcssa)) + 1|0);
-  $5 = HEAP8[$arrayidx31>>0]|0;
-  $conv32 = $5 << 24 >> 24;
-  $isdigittmp = (($conv32) + -48)|0;
-  $isdigit = ($isdigittmp>>>0)<(10);
-  if ($isdigit) {
-   $arrayidx35 = ((($incdec$ptr169276$lcssa)) + 2|0);
-   $6 = HEAP8[$arrayidx35>>0]|0;
-   $cmp37 = ($6<<24>>24)==(36);
-   $add$ptr43 = ((($incdec$ptr169276$lcssa)) + 3|0);
-   $add$ptr43$arrayidx31 = $cmp37 ? $add$ptr43 : $arrayidx31;
-   $$l10n$0 = $cmp37 ? 1 : $l10n$0;
-   $isdigittmp$ = $cmp37 ? $isdigittmp : -1;
-   $$pre357 = HEAP8[$add$ptr43$arrayidx31>>0]|0;
-   $7 = $$pre357;$argpos$0 = $isdigittmp$;$l10n$1 = $$l10n$0;$storemerge = $add$ptr43$arrayidx31;
-  } else {
-   $7 = $5;$argpos$0 = -1;$l10n$1 = $l10n$0;$storemerge = $arrayidx31;
-  }
-  $conv48$307 = $7 << 24 >> 24;
-  $8 = $conv48$307 & -32;
-  $cmp50$308 = ($8|0)==(32);
-  L25: do {
-   if ($cmp50$308) {
-    $9 = $7;$conv48311 = $conv48$307;$fl$0310 = 0;$storemerge$186309 = $storemerge;
-    while(1) {
-     $sub54 = (($conv48311) + -32)|0;
-     $shl = 1 << $sub54;
-     $and = $shl & 75913;
-     $tobool55 = ($and|0)==(0);
-     if ($tobool55) {
-      $12 = $9;$fl$0284 = $fl$0310;$storemerge$186282 = $storemerge$186309;
-      break L25;
-     }
-     $conv58 = $9 << 24 >> 24;
-     $sub59 = (($conv58) + -32)|0;
-     $shl60 = 1 << $sub59;
-     $or = $shl60 | $fl$0310;
-     $incdec$ptr62 = ((($storemerge$186309)) + 1|0);
-     $10 = HEAP8[$incdec$ptr62>>0]|0;
-     $conv48 = $10 << 24 >> 24;
-     $11 = $conv48 & -32;
-     $cmp50 = ($11|0)==(32);
-     if ($cmp50) {
-      $9 = $10;$conv48311 = $conv48;$fl$0310 = $or;$storemerge$186309 = $incdec$ptr62;
-     } else {
-      $12 = $10;$fl$0284 = $or;$storemerge$186282 = $incdec$ptr62;
-      break;
-     }
-    }
-   } else {
-    $12 = $7;$fl$0284 = 0;$storemerge$186282 = $storemerge;
-   }
-  } while(0);
-  $cmp65 = ($12<<24>>24)==(42);
-  do {
-   if ($cmp65) {
-    $arrayidx68 = ((($storemerge$186282)) + 1|0);
-    $13 = HEAP8[$arrayidx68>>0]|0;
-    $conv69 = $13 << 24 >> 24;
-    $isdigittmp189 = (($conv69) + -48)|0;
-    $isdigit190 = ($isdigittmp189>>>0)<(10);
-    if ($isdigit190) {
-     $arrayidx73 = ((($storemerge$186282)) + 2|0);
-     $14 = HEAP8[$arrayidx73>>0]|0;
-     $cmp75 = ($14<<24>>24)==(36);
-     if ($cmp75) {
-      $arrayidx81 = (($nl_type) + ($isdigittmp189<<2)|0);
-      HEAP32[$arrayidx81>>2] = 10;
-      $15 = HEAP8[$arrayidx68>>0]|0;
-      $conv83 = $15 << 24 >> 24;
-      $sub84 = (($conv83) + -48)|0;
-      $i86 = (($nl_arg) + ($sub84<<3)|0);
-      $16 = $i86;
-      $17 = $16;
-      $18 = HEAP32[$17>>2]|0;
-      $19 = (($16) + 4)|0;
-      $20 = $19;
-      $21 = HEAP32[$20>>2]|0;
-      $add$ptr88 = ((($storemerge$186282)) + 3|0);
-      $l10n$2 = 1;$storemerge$191 = $add$ptr88;$w$0 = $18;
-     } else {
-      label = 24;
-     }
-    } else {
-     label = 24;
-    }
-    if ((label|0) == 24) {
-     label = 0;
-     $tobool90 = ($l10n$1|0)==(0);
-     if (!($tobool90)) {
-      $retval$0 = -1;
-      break L1;
-     }
-     if (!($tobool25)) {
-      $fl$1 = $fl$0284;$incdec$ptr169269 = $arrayidx68;$l10n$3 = 0;$w$1 = 0;
-      break;
-     }
-     $arglist_current = HEAP32[$ap>>2]|0;
-     $22 = $arglist_current;
-     $23 = ((0) + 4|0);
-     $expanded4 = $23;
-     $expanded = (($expanded4) - 1)|0;
-     $24 = (($22) + ($expanded))|0;
-     $25 = ((0) + 4|0);
-     $expanded8 = $25;
-     $expanded7 = (($expanded8) - 1)|0;
-     $expanded6 = $expanded7 ^ -1;
-     $26 = $24 & $expanded6;
-     $27 = $26;
-     $28 = HEAP32[$27>>2]|0;
-     $arglist_next = ((($27)) + 4|0);
-     HEAP32[$ap>>2] = $arglist_next;
-     $l10n$2 = 0;$storemerge$191 = $arrayidx68;$w$0 = $28;
-    }
-    $cmp97 = ($w$0|0)<(0);
-    if ($cmp97) {
-     $or100 = $fl$0284 | 8192;
-     $sub101 = (0 - ($w$0))|0;
-     $fl$1 = $or100;$incdec$ptr169269 = $storemerge$191;$l10n$3 = $l10n$2;$w$1 = $sub101;
-    } else {
-     $fl$1 = $fl$0284;$incdec$ptr169269 = $storemerge$191;$l10n$3 = $l10n$2;$w$1 = $w$0;
-    }
-   } else {
-    $conv$4$i = $12 << 24 >> 24;
-    $isdigittmp$5$i = (($conv$4$i) + -48)|0;
-    $isdigit$6$i = ($isdigittmp$5$i>>>0)<(10);
-    if ($isdigit$6$i) {
-     $29 = $storemerge$186282;$i$07$i = 0;$isdigittmp8$i = $isdigittmp$5$i;
-     while(1) {
-      $mul$i = ($i$07$i*10)|0;
-      $add$i = (($mul$i) + ($isdigittmp8$i))|0;
-      $incdec$ptr$i = ((($29)) + 1|0);
-      $30 = HEAP8[$incdec$ptr$i>>0]|0;
-      $conv$i = $30 << 24 >> 24;
-      $isdigittmp$i = (($conv$i) + -48)|0;
-      $isdigit$i = ($isdigittmp$i>>>0)<(10);
-      if ($isdigit$i) {
-       $29 = $incdec$ptr$i;$i$07$i = $add$i;$isdigittmp8$i = $isdigittmp$i;
-      } else {
-       $add$i$lcssa = $add$i;$incdec$ptr$i$lcssa = $incdec$ptr$i;
-       break;
-      }
-     }
-     $cmp105 = ($add$i$lcssa|0)<(0);
-     if ($cmp105) {
-      $retval$0 = -1;
-      break L1;
-     } else {
-      $fl$1 = $fl$0284;$incdec$ptr169269 = $incdec$ptr$i$lcssa;$l10n$3 = $l10n$1;$w$1 = $add$i$lcssa;
-     }
-    } else {
-     $fl$1 = $fl$0284;$incdec$ptr169269 = $storemerge$186282;$l10n$3 = $l10n$1;$w$1 = 0;
-    }
-   }
-  } while(0);
-  $31 = HEAP8[$incdec$ptr169269>>0]|0;
-  $cmp111 = ($31<<24>>24)==(46);
-  L46: do {
-   if ($cmp111) {
-    $arrayidx114 = ((($incdec$ptr169269)) + 1|0);
-    $32 = HEAP8[$arrayidx114>>0]|0;
-    $cmp116 = ($32<<24>>24)==(42);
-    if (!($cmp116)) {
-     $conv$4$i$197 = $32 << 24 >> 24;
-     $isdigittmp$5$i$198 = (($conv$4$i$197) + -48)|0;
-     $isdigit$6$i$199 = ($isdigittmp$5$i$198>>>0)<(10);
-     if ($isdigit$6$i$199) {
-      $49 = $arrayidx114;$i$07$i$201 = 0;$isdigittmp8$i$200 = $isdigittmp$5$i$198;
-     } else {
-      $incdec$ptr169272 = $arrayidx114;$p$0 = 0;
-      break;
-     }
-     while(1) {
-      $mul$i$202 = ($i$07$i$201*10)|0;
-      $add$i$203 = (($mul$i$202) + ($isdigittmp8$i$200))|0;
-      $incdec$ptr$i$204 = ((($49)) + 1|0);
-      $50 = HEAP8[$incdec$ptr$i$204>>0]|0;
-      $conv$i$205 = $50 << 24 >> 24;
-      $isdigittmp$i$206 = (($conv$i$205) + -48)|0;
-      $isdigit$i$207 = ($isdigittmp$i$206>>>0)<(10);
-      if ($isdigit$i$207) {
-       $49 = $incdec$ptr$i$204;$i$07$i$201 = $add$i$203;$isdigittmp8$i$200 = $isdigittmp$i$206;
-      } else {
-       $incdec$ptr169272 = $incdec$ptr$i$204;$p$0 = $add$i$203;
-       break L46;
-      }
-     }
-    }
-    $arrayidx119 = ((($incdec$ptr169269)) + 2|0);
-    $33 = HEAP8[$arrayidx119>>0]|0;
-    $conv120 = $33 << 24 >> 24;
-    $isdigittmp187 = (($conv120) + -48)|0;
-    $isdigit188 = ($isdigittmp187>>>0)<(10);
-    if ($isdigit188) {
-     $arrayidx124 = ((($incdec$ptr169269)) + 3|0);
-     $34 = HEAP8[$arrayidx124>>0]|0;
-     $cmp126 = ($34<<24>>24)==(36);
-     if ($cmp126) {
-      $arrayidx132 = (($nl_type) + ($isdigittmp187<<2)|0);
-      HEAP32[$arrayidx132>>2] = 10;
-      $35 = HEAP8[$arrayidx119>>0]|0;
-      $conv134 = $35 << 24 >> 24;
-      $sub135 = (($conv134) + -48)|0;
-      $i137 = (($nl_arg) + ($sub135<<3)|0);
-      $36 = $i137;
-      $37 = $36;
-      $38 = HEAP32[$37>>2]|0;
-      $39 = (($36) + 4)|0;
-      $40 = $39;
-      $41 = HEAP32[$40>>2]|0;
-      $add$ptr139 = ((($incdec$ptr169269)) + 4|0);
-      $incdec$ptr169272 = $add$ptr139;$p$0 = $38;
-      break;
-     }
-    }
-    $tobool141 = ($l10n$3|0)==(0);
-    if (!($tobool141)) {
-     $retval$0 = -1;
-     break L1;
-    }
-    if ($tobool25) {
-     $arglist_current2 = HEAP32[$ap>>2]|0;
-     $42 = $arglist_current2;
-     $43 = ((0) + 4|0);
-     $expanded11 = $43;
-     $expanded10 = (($expanded11) - 1)|0;
-     $44 = (($42) + ($expanded10))|0;
-     $45 = ((0) + 4|0);
-     $expanded15 = $45;
-     $expanded14 = (($expanded15) - 1)|0;
-     $expanded13 = $expanded14 ^ -1;
-     $46 = $44 & $expanded13;
-     $47 = $46;
-     $48 = HEAP32[$47>>2]|0;
-     $arglist_next3 = ((($47)) + 4|0);
-     HEAP32[$ap>>2] = $arglist_next3;
-     $incdec$ptr169272 = $arrayidx119;$p$0 = $48;
-    } else {
-     $incdec$ptr169272 = $arrayidx119;$p$0 = 0;
-    }
-   } else {
-    $incdec$ptr169272 = $incdec$ptr169269;$p$0 = -1;
-   }
-  } while(0);
-  $incdec$ptr169271 = $incdec$ptr169272;$st$0 = 0;
-  while(1) {
-   $51 = HEAP8[$incdec$ptr169271>>0]|0;
-   $conv163 = $51 << 24 >> 24;
-   $sub164 = (($conv163) + -65)|0;
-   $cmp165 = ($sub164>>>0)>(57);
-   if ($cmp165) {
-    $retval$0 = -1;
-    break L1;
-   }
-   $incdec$ptr169 = ((($incdec$ptr169271)) + 1|0);
-   $arrayidx173 = ((3611 + (($st$0*58)|0)|0) + ($sub164)|0);
-   $52 = HEAP8[$arrayidx173>>0]|0;
-   $conv174 = $52&255;
-   $sub175 = (($conv174) + -1)|0;
-   $cmp176 = ($sub175>>>0)<(8);
-   if ($cmp176) {
-    $incdec$ptr169271 = $incdec$ptr169;$st$0 = $conv174;
-   } else {
-    $$lcssa = $52;$conv174$lcssa = $conv174;$incdec$ptr169$lcssa = $incdec$ptr169;$incdec$ptr169271$lcssa414 = $incdec$ptr169271;$st$0$lcssa415 = $st$0;
-    break;
-   }
-  }
-  $tobool178 = ($$lcssa<<24>>24)==(0);
-  if ($tobool178) {
-   $retval$0 = -1;
-   break;
-  }
-  $cmp181 = ($$lcssa<<24>>24)==(19);
-  $cmp184 = ($argpos$0|0)>(-1);
-  do {
-   if ($cmp181) {
-    if ($cmp184) {
-     $retval$0 = -1;
-     break L1;
-    } else {
-     label = 52;
-    }
-   } else {
-    if ($cmp184) {
-     $arrayidx192 = (($nl_type) + ($argpos$0<<2)|0);
-     HEAP32[$arrayidx192>>2] = $conv174$lcssa;
-     $53 = (($nl_arg) + ($argpos$0<<3)|0);
-     $54 = $53;
-     $55 = $54;
-     $56 = HEAP32[$55>>2]|0;
-     $57 = (($54) + 4)|0;
-     $58 = $57;
-     $59 = HEAP32[$58>>2]|0;
-     $60 = $arg;
-     $61 = $60;
-     HEAP32[$61>>2] = $56;
-     $62 = (($60) + 4)|0;
-     $63 = $62;
-     HEAP32[$63>>2] = $59;
-     label = 52;
-     break;
-    }
-    if (!($tobool25)) {
-     $retval$0 = 0;
-     break L1;
-    }
-    _pop_arg_336($arg,$conv174$lcssa,$ap);
-   }
-  } while(0);
-  if ((label|0) == 52) {
-   label = 0;
-   if (!($tobool25)) {
-    $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$3;
-    continue;
-   }
-  }
-  $64 = HEAP8[$incdec$ptr169271$lcssa414>>0]|0;
-  $conv207 = $64 << 24 >> 24;
-  $tobool208 = ($st$0$lcssa415|0)!=(0);
-  $and210 = $conv207 & 15;
-  $cmp211 = ($and210|0)==(3);
-  $or$cond192 = $tobool208 & $cmp211;
-  $and214 = $conv207 & -33;
-  $t$0 = $or$cond192 ? $and214 : $conv207;
-  $and216 = $fl$1 & 8192;
-  $tobool217 = ($and216|0)==(0);
-  $and219 = $fl$1 & -65537;
-  $fl$1$and219 = $tobool217 ? $fl$1 : $and219;
-  L75: do {
-   switch ($t$0|0) {
-   case 110:  {
-    switch ($st$0$lcssa415|0) {
-    case 0:  {
-     $71 = HEAP32[$arg>>2]|0;
-     HEAP32[$71>>2] = $cnt$1;
-     $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$3;
-     continue L1;
-     break;
-    }
-    case 1:  {
-     $72 = HEAP32[$arg>>2]|0;
-     HEAP32[$72>>2] = $cnt$1;
-     $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$3;
-     continue L1;
-     break;
-    }
-    case 2:  {
-     $73 = ($cnt$1|0)<(0);
-     $74 = $73 << 31 >> 31;
-     $75 = HEAP32[$arg>>2]|0;
-     $76 = $75;
-     $77 = $76;
-     HEAP32[$77>>2] = $cnt$1;
-     $78 = (($76) + 4)|0;
-     $79 = $78;
-     HEAP32[$79>>2] = $74;
-     $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$3;
-     continue L1;
-     break;
-    }
-    case 3:  {
-     $conv229 = $cnt$1&65535;
-     $80 = HEAP32[$arg>>2]|0;
-     HEAP16[$80>>1] = $conv229;
-     $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$3;
-     continue L1;
-     break;
-    }
-    case 4:  {
-     $conv232 = $cnt$1&255;
-     $81 = HEAP32[$arg>>2]|0;
-     HEAP8[$81>>0] = $conv232;
-     $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$3;
-     continue L1;
-     break;
-    }
-    case 6:  {
-     $82 = HEAP32[$arg>>2]|0;
-     HEAP32[$82>>2] = $cnt$1;
-     $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$3;
-     continue L1;
-     break;
-    }
-    case 7:  {
-     $83 = ($cnt$1|0)<(0);
-     $84 = $83 << 31 >> 31;
-     $85 = HEAP32[$arg>>2]|0;
-     $86 = $85;
-     $87 = $86;
-     HEAP32[$87>>2] = $cnt$1;
-     $88 = (($86) + 4)|0;
-     $89 = $88;
-     HEAP32[$89>>2] = $84;
-     $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$3;
-     continue L1;
-     break;
-    }
-    default: {
-     $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $sub$ptr$sub;$l10n$0 = $l10n$3;
-     continue L1;
-    }
-    }
-    break;
-   }
-   case 112:  {
-    $cmp240 = ($p$0>>>0)>(8);
-    $cond245 = $cmp240 ? $p$0 : 8;
-    $or246 = $fl$1$and219 | 8;
-    $fl$3 = $or246;$p$1 = $cond245;$t$1 = 120;
-    label = 64;
-    break;
-   }
-   case 88: case 120:  {
-    $fl$3 = $fl$1$and219;$p$1 = $p$0;$t$1 = $t$0;
-    label = 64;
-    break;
-   }
-   case 111:  {
-    $116 = $arg;
-    $117 = $116;
-    $118 = HEAP32[$117>>2]|0;
-    $119 = (($116) + 4)|0;
-    $120 = $119;
-    $121 = HEAP32[$120>>2]|0;
-    $122 = ($118|0)==(0);
-    $123 = ($121|0)==(0);
-    $124 = $122 & $123;
-    if ($124) {
-     $s$addr$0$lcssa$i$229 = $add$ptr205;
-    } else {
-     $126 = $118;$129 = $121;$s$addr$06$i$221 = $add$ptr205;
-     while(1) {
-      $125 = $126 & 7;
-      $127 = $125 | 48;
-      $128 = $127&255;
-      $incdec$ptr$i$225 = ((($s$addr$06$i$221)) + -1|0);
-      HEAP8[$incdec$ptr$i$225>>0] = $128;
-      $130 = (_bitshift64Lshr(($126|0),($129|0),3)|0);
-      $131 = tempRet0;
-      $132 = ($130|0)==(0);
-      $133 = ($131|0)==(0);
-      $134 = $132 & $133;
-      if ($134) {
-       $s$addr$0$lcssa$i$229 = $incdec$ptr$i$225;
-       break;
-      } else {
-       $126 = $130;$129 = $131;$s$addr$06$i$221 = $incdec$ptr$i$225;
-      }
-     }
-    }
-    $and263 = $fl$1$and219 & 8;
-    $tobool264 = ($and263|0)==(0);
-    if ($tobool264) {
-     $a$0 = $s$addr$0$lcssa$i$229;$fl$4 = $fl$1$and219;$p$2 = $p$0;$pl$1 = 0;$prefix$1 = 4091;
-     label = 77;
-    } else {
-     $sub$ptr$rhs$cast267 = $s$addr$0$lcssa$i$229;
-     $sub$ptr$sub268 = (($sub$ptr$lhs$cast317) - ($sub$ptr$rhs$cast267))|0;
-     $add269 = (($sub$ptr$sub268) + 1)|0;
-     $cmp270 = ($p$0|0)<($add269|0);
-     $add269$p$0 = $cmp270 ? $add269 : $p$0;
-     $a$0 = $s$addr$0$lcssa$i$229;$fl$4 = $fl$1$and219;$p$2 = $add269$p$0;$pl$1 = 0;$prefix$1 = 4091;
-     label = 77;
-    }
-    break;
-   }
-   case 105: case 100:  {
-    $135 = $arg;
-    $136 = $135;
-    $137 = HEAP32[$136>>2]|0;
-    $138 = (($135) + 4)|0;
-    $139 = $138;
-    $140 = HEAP32[$139>>2]|0;
-    $141 = ($140|0)<(0);
-    if ($141) {
-     $142 = (_i64Subtract(0,0,($137|0),($140|0))|0);
-     $143 = tempRet0;
-     $144 = $arg;
-     $145 = $144;
-     HEAP32[$145>>2] = $142;
-     $146 = (($144) + 4)|0;
-     $147 = $146;
-     HEAP32[$147>>2] = $143;
-     $148 = $142;$149 = $143;$pl$0 = 1;$prefix$0 = 4091;
-     label = 76;
-     break L75;
-    }
-    $and289 = $fl$1$and219 & 2048;
-    $tobool290 = ($and289|0)==(0);
-    if ($tobool290) {
-     $and294 = $fl$1$and219 & 1;
-     $tobool295 = ($and294|0)==(0);
-     $$ = $tobool295 ? 4091 : (4093);
-     $148 = $137;$149 = $140;$pl$0 = $and294;$prefix$0 = $$;
-     label = 76;
-    } else {
-     $148 = $137;$149 = $140;$pl$0 = 1;$prefix$0 = (4092);
-     label = 76;
-    }
-    break;
-   }
-   case 117:  {
-    $65 = $arg;
-    $66 = $65;
-    $67 = HEAP32[$66>>2]|0;
-    $68 = (($65) + 4)|0;
-    $69 = $68;
-    $70 = HEAP32[$69>>2]|0;
-    $148 = $67;$149 = $70;$pl$0 = 0;$prefix$0 = 4091;
-    label = 76;
-    break;
-   }
-   case 99:  {
-    $161 = $arg;
-    $162 = $161;
-    $163 = HEAP32[$162>>2]|0;
-    $164 = (($161) + 4)|0;
-    $165 = $164;
-    $166 = HEAP32[$165>>2]|0;
-    $167 = $163&255;
-    HEAP8[$add$ptr340>>0] = $167;
-    $a$2 = $add$ptr340;$fl$6 = $and219;$p$5 = 1;$pl$2 = 0;$prefix$2 = 4091;$z$2 = $add$ptr205;
-    break;
-   }
-   case 109:  {
-    $call344 = (___errno_location()|0);
-    $168 = HEAP32[$call344>>2]|0;
-    $call345 = (_strerror($168)|0);
-    $a$1 = $call345;
-    label = 82;
-    break;
-   }
-   case 115:  {
-    $169 = HEAP32[$arg>>2]|0;
-    $tobool349 = ($169|0)!=(0|0);
-    $cond354 = $tobool349 ? $169 : 4101;
-    $a$1 = $cond354;
-    label = 82;
-    break;
-   }
-   case 67:  {
-    $170 = $arg;
-    $171 = $170;
-    $172 = HEAP32[$171>>2]|0;
-    $173 = (($170) + 4)|0;
-    $174 = $173;
-    $175 = HEAP32[$174>>2]|0;
-    HEAP32[$wc>>2] = $172;
-    HEAP32[$arrayidx370>>2] = 0;
-    HEAP32[$arg>>2] = $wc;
-    $p$4365 = -1;
-    label = 86;
-    break;
-   }
-   case 83:  {
-    $cmp377$314 = ($p$0|0)==(0);
-    if ($cmp377$314) {
-     _pad($f,32,$w$1,0,$fl$1$and219);
-     $i$0$lcssa368 = 0;
-     label = 98;
-    } else {
-     $p$4365 = $p$0;
-     label = 86;
-    }
-    break;
-   }
-   case 65: case 71: case 70: case 69: case 97: case 103: case 102: case 101:  {
-    $181 = +HEAPF64[$arg>>3];
-    HEAP32[$e2$i>>2] = 0;
-    HEAPF64[tempDoublePtr>>3] = $181;$182 = HEAP32[tempDoublePtr>>2]|0;
-    $183 = HEAP32[tempDoublePtr+4>>2]|0;
-    $184 = ($183|0)<(0);
-    if ($184) {
-     $sub$i = -$181;
-     $pl$0$i = 1;$prefix$0$i = 4108;$y$addr$0$i = $sub$i;
-    } else {
-     $and$i$238 = $fl$1$and219 & 2048;
-     $tobool9$i = ($and$i$238|0)==(0);
-     if ($tobool9$i) {
-      $and12$i = $fl$1$and219 & 1;
-      $tobool13$i = ($and12$i|0)==(0);
-      $$$i = $tobool13$i ? (4109) : (4114);
-      $pl$0$i = $and12$i;$prefix$0$i = $$$i;$y$addr$0$i = $181;
-     } else {
-      $pl$0$i = 1;$prefix$0$i = (4111);$y$addr$0$i = $181;
-     }
-    }
-    HEAPF64[tempDoublePtr>>3] = $y$addr$0$i;$185 = HEAP32[tempDoublePtr>>2]|0;
-    $186 = HEAP32[tempDoublePtr+4>>2]|0;
-    $187 = $186 & 2146435072;
-    $188 = ($187>>>0)<(2146435072);
-    $189 = (0)<(0);
-    $190 = ($187|0)==(2146435072);
-    $191 = $190 & $189;
-    $192 = $188 | $191;
-    do {
-     if ($192) {
-      $call55$i = (+_frexpl($y$addr$0$i,$e2$i));
-      $mul$i$240 = $call55$i * 2.0;
-      $tobool56$i = $mul$i$240 != 0.0;
-      if ($tobool56$i) {
-       $195 = HEAP32[$e2$i>>2]|0;
-       $dec$i = (($195) + -1)|0;
-       HEAP32[$e2$i>>2] = $dec$i;
-      }
-      $or$i$241 = $t$0 | 32;
-      $cmp59$i = ($or$i$241|0)==(97);
-      if ($cmp59$i) {
-       $and62$i = $t$0 & 32;
-       $tobool63$i = ($and62$i|0)==(0);
-       $add$ptr65$i = ((($prefix$0$i)) + 9|0);
-       $prefix$0$add$ptr65$i = $tobool63$i ? $prefix$0$i : $add$ptr65$i;
-       $add67$i = $pl$0$i | 2;
-       $196 = ($p$0>>>0)>(11);
-       $sub74$i = (12 - ($p$0))|0;
-       $tobool76552$i = ($sub74$i|0)==(0);
-       $tobool76$i = $196 | $tobool76552$i;
-       do {
-        if ($tobool76$i) {
-         $y$addr$1$i = $mul$i$240;
-        } else {
-         $re$1482$i = $sub74$i;$round$0481$i = 8.0;
-         while(1) {
-          $dec78$i = (($re$1482$i) + -1)|0;
-          $mul80$i = $round$0481$i * 16.0;
-          $tobool79$i = ($dec78$i|0)==(0);
-          if ($tobool79$i) {
-           $mul80$i$lcssa = $mul80$i;
-           break;
-          } else {
-           $re$1482$i = $dec78$i;$round$0481$i = $mul80$i;
-          }
-         }
-         $197 = HEAP8[$prefix$0$add$ptr65$i>>0]|0;
-         $cmp82$i = ($197<<24>>24)==(45);
-         if ($cmp82$i) {
-          $sub85$i = -$mul$i$240;
-          $sub86$i = $sub85$i - $mul80$i$lcssa;
-          $add87$i = $mul80$i$lcssa + $sub86$i;
-          $sub88$i = -$add87$i;
-          $y$addr$1$i = $sub88$i;
-          break;
-         } else {
-          $add90$i = $mul$i$240 + $mul80$i$lcssa;
-          $sub91$i = $add90$i - $mul80$i$lcssa;
-          $y$addr$1$i = $sub91$i;
-          break;
-         }
-        }
-       } while(0);
-       $198 = HEAP32[$e2$i>>2]|0;
-       $cmp94$i = ($198|0)<(0);
-       $sub97$i = (0 - ($198))|0;
-       $cond100$i = $cmp94$i ? $sub97$i : $198;
-       $199 = ($cond100$i|0)<(0);
-       $200 = $199 << 31 >> 31;
-       $201 = (_fmt_u($cond100$i,$200,$arrayidx$i$236)|0);
-       $cmp103$i = ($201|0)==($arrayidx$i$236|0);
-       if ($cmp103$i) {
-        HEAP8[$incdec$ptr106$i>>0] = 48;
-        $estr$0$i = $incdec$ptr106$i;
-       } else {
-        $estr$0$i = $201;
-       }
-       $202 = $198 >> 31;
-       $203 = $202 & 2;
-       $204 = (($203) + 43)|0;
-       $conv111$i = $204&255;
-       $incdec$ptr112$i = ((($estr$0$i)) + -1|0);
-       HEAP8[$incdec$ptr112$i>>0] = $conv111$i;
-       $add113$i = (($t$0) + 15)|0;
-       $conv114$i = $add113$i&255;
-       $incdec$ptr115$i = ((($estr$0$i)) + -2|0);
-       HEAP8[$incdec$ptr115$i>>0] = $conv114$i;
-       $notrhs$i = ($p$0|0)<(1);
-       $and134$i = $fl$1$and219 & 8;
-       $tobool135$i = ($and134$i|0)==(0);
-       $s$0$i = $buf$i;$y$addr$2$i = $y$addr$1$i;
-       while(1) {
-        $conv116$i = (~~(($y$addr$2$i)));
-        $arrayidx117$i = (4075 + ($conv116$i)|0);
-        $205 = HEAP8[$arrayidx117$i>>0]|0;
-        $conv118$393$i = $205&255;
-        $or120$i = $conv118$393$i | $and62$i;
-        $conv121$i = $or120$i&255;
-        $incdec$ptr122$i = ((($s$0$i)) + 1|0);
-        HEAP8[$s$0$i>>0] = $conv121$i;
-        $conv123$i = (+($conv116$i|0));
-        $sub124$i = $y$addr$2$i - $conv123$i;
-        $mul125$i = $sub124$i * 16.0;
-        $sub$ptr$lhs$cast$i = $incdec$ptr122$i;
-        $sub$ptr$sub$i = (($sub$ptr$lhs$cast$i) - ($sub$ptr$rhs$cast$i))|0;
-        $cmp127$i = ($sub$ptr$sub$i|0)==(1);
-        do {
-         if ($cmp127$i) {
-          $notlhs$i = $mul125$i == 0.0;
-          $or$cond1$not$i = $notrhs$i & $notlhs$i;
-          $or$cond$i = $tobool135$i & $or$cond1$not$i;
-          if ($or$cond$i) {
-           $s$1$i = $incdec$ptr122$i;
-           break;
-          }
-          $incdec$ptr137$i = ((($s$0$i)) + 2|0);
-          HEAP8[$incdec$ptr122$i>>0] = 46;
-          $s$1$i = $incdec$ptr137$i;
-         } else {
-          $s$1$i = $incdec$ptr122$i;
-         }
-        } while(0);
-        $tobool139$i = $mul125$i != 0.0;
-        if ($tobool139$i) {
-         $s$0$i = $s$1$i;$y$addr$2$i = $mul125$i;
-        } else {
-         $s$1$i$lcssa = $s$1$i;
-         break;
-        }
-       }
-       $tobool140$i = ($p$0|0)!=(0);
-       $$pre566$i = $s$1$i$lcssa;
-       $sub146$i = (($sub$ptr$sub145$i) + ($$pre566$i))|0;
-       $cmp147$i = ($sub146$i|0)<($p$0|0);
-       $or$cond384 = $tobool140$i & $cmp147$i;
-       $sub$ptr$rhs$cast152$i = $incdec$ptr115$i;
-       $add150$i = (($sub$ptr$sub153$i) + ($p$0))|0;
-       $add154$i = (($add150$i) - ($sub$ptr$rhs$cast152$i))|0;
-       $sub$ptr$rhs$cast161$i = $incdec$ptr115$i;
-       $sub$ptr$sub162$i = (($sub$ptr$sub159$i) - ($sub$ptr$rhs$cast161$i))|0;
-       $add163$i = (($sub$ptr$sub162$i) + ($$pre566$i))|0;
-       $l$0$i = $or$cond384 ? $add154$i : $add163$i;
-       $add165$i = (($l$0$i) + ($add67$i))|0;
-       _pad($f,32,$w$1,$add165$i,$fl$1$and219);
-       $206 = HEAP32[$f>>2]|0;
-       $and$i$418$i = $206 & 32;
-       $tobool$i$419$i = ($and$i$418$i|0)==(0);
-       if ($tobool$i$419$i) {
-        (___fwritex($prefix$0$add$ptr65$i,$add67$i,$f)|0);
-       }
-       $xor167$i = $fl$1$and219 ^ 65536;
-       _pad($f,48,$w$1,$add165$i,$xor167$i);
-       $sub$ptr$sub172$i = (($$pre566$i) - ($sub$ptr$rhs$cast$i))|0;
-       $207 = HEAP32[$f>>2]|0;
-       $and$i$424$i = $207 & 32;
-       $tobool$i$425$i = ($and$i$424$i|0)==(0);
-       if ($tobool$i$425$i) {
-        (___fwritex($buf$i,$sub$ptr$sub172$i,$f)|0);
-       }
-       $sub$ptr$rhs$cast174$i = $incdec$ptr115$i;
-       $sub$ptr$sub175$i = (($sub$ptr$lhs$cast160$i) - ($sub$ptr$rhs$cast174$i))|0;
-       $sum = (($sub$ptr$sub172$i) + ($sub$ptr$sub175$i))|0;
-       $sub181$i = (($l$0$i) - ($sum))|0;
-       _pad($f,48,$sub181$i,0,0);
-       $208 = HEAP32[$f>>2]|0;
-       $and$i$430$i = $208 & 32;
-       $tobool$i$431$i = ($and$i$430$i|0)==(0);
-       if ($tobool$i$431$i) {
-        (___fwritex($incdec$ptr115$i,$sub$ptr$sub175$i,$f)|0);
-       }
-       $xor186$i = $fl$1$and219 ^ 8192;
-       _pad($f,32,$w$1,$add165$i,$xor186$i);
-       $cmp188$i = ($add165$i|0)<($w$1|0);
-       $w$add165$i = $cmp188$i ? $w$1 : $add165$i;
-       $retval$0$i = $w$add165$i;
-       break;
-      }
-      $cmp196$i = ($p$0|0)<(0);
-      $$p$i = $cmp196$i ? 6 : $p$0;
-      if ($tobool56$i) {
-       $mul202$i = $mul$i$240 * 268435456.0;
-       $209 = HEAP32[$e2$i>>2]|0;
-       $sub203$i = (($209) + -28)|0;
-       HEAP32[$e2$i>>2] = $sub203$i;
-       $210 = $sub203$i;$y$addr$3$i = $mul202$i;
-      } else {
-       $$pre564$i = HEAP32[$e2$i>>2]|0;
-       $210 = $$pre564$i;$y$addr$3$i = $mul$i$240;
-      }
-      $cmp205$i = ($210|0)<(0);
-      $arraydecay208$add$ptr213$i = $cmp205$i ? $big$i : $add$ptr213$i;
-      $sub$ptr$rhs$cast345$i = $arraydecay208$add$ptr213$i;
-      $y$addr$4$i = $y$addr$3$i;$z$0$i = $arraydecay208$add$ptr213$i;
-      while(1) {
-       $conv216$i = (~~(($y$addr$4$i))>>>0);
-       HEAP32[$z$0$i>>2] = $conv216$i;
-       $incdec$ptr217$i = ((($z$0$i)) + 4|0);
-       $conv218$i = (+($conv216$i>>>0));
-       $sub219$i = $y$addr$4$i - $conv218$i;
-       $mul220$i = $sub219$i * 1.0E+9;
-       $tobool222$i = $mul220$i != 0.0;
-       if ($tobool222$i) {
-        $y$addr$4$i = $mul220$i;$z$0$i = $incdec$ptr217$i;
-       } else {
-        $incdec$ptr217$i$lcssa = $incdec$ptr217$i;
-        break;
-       }
-      }
-      $$pr$i = HEAP32[$e2$i>>2]|0;
-      $cmp225$547$i = ($$pr$i|0)>(0);
-      if ($cmp225$547$i) {
-       $211 = $$pr$i;$a$1549$i = $arraydecay208$add$ptr213$i;$z$1548$i = $incdec$ptr217$i$lcssa;
-       while(1) {
-        $cmp228$i = ($211|0)>(29);
-        $cond233$i = $cmp228$i ? 29 : $211;
-        $d$0$542$i = ((($z$1548$i)) + -4|0);
-        $cmp235$543$i = ($d$0$542$i>>>0)<($a$1549$i>>>0);
-        do {
-         if ($cmp235$543$i) {
-          $a$2$ph$i = $a$1549$i;
-         } else {
-          $carry$0544$i = 0;$d$0545$i = $d$0$542$i;
-          while(1) {
-           $212 = HEAP32[$d$0545$i>>2]|0;
-           $213 = (_bitshift64Shl(($212|0),0,($cond233$i|0))|0);
-           $214 = tempRet0;
-           $215 = (_i64Add(($213|0),($214|0),($carry$0544$i|0),0)|0);
-           $216 = tempRet0;
-           $217 = (___uremdi3(($215|0),($216|0),1000000000,0)|0);
-           $218 = tempRet0;
-           HEAP32[$d$0545$i>>2] = $217;
-           $219 = (___udivdi3(($215|0),($216|0),1000000000,0)|0);
-           $220 = tempRet0;
-           $d$0$i = ((($d$0545$i)) + -4|0);
-           $cmp235$i = ($d$0$i>>>0)<($a$1549$i>>>0);
-           if ($cmp235$i) {
-            $conv242$i$lcssa = $219;
-            break;
-           } else {
-            $carry$0544$i = $219;$d$0545$i = $d$0$i;
-           }
-          }
-          $tobool244$i = ($conv242$i$lcssa|0)==(0);
-          if ($tobool244$i) {
-           $a$2$ph$i = $a$1549$i;
-           break;
-          }
-          $incdec$ptr246$i = ((($a$1549$i)) + -4|0);
-          HEAP32[$incdec$ptr246$i>>2] = $conv242$i$lcssa;
-          $a$2$ph$i = $incdec$ptr246$i;
-         }
-        } while(0);
-        $z$2$i = $z$1548$i;
-        while(1) {
-         $cmp249$i = ($z$2$i>>>0)>($a$2$ph$i>>>0);
-         if (!($cmp249$i)) {
-          $z$2$i$lcssa = $z$2$i;
-          break;
-         }
-         $arrayidx251$i = ((($z$2$i)) + -4|0);
-         $221 = HEAP32[$arrayidx251$i>>2]|0;
-         $lnot$i = ($221|0)==(0);
-         if ($lnot$i) {
-          $z$2$i = $arrayidx251$i;
-         } else {
-          $z$2$i$lcssa = $z$2$i;
-          break;
-         }
-        }
-        $222 = HEAP32[$e2$i>>2]|0;
-        $sub256$i = (($222) - ($cond233$i))|0;
-        HEAP32[$e2$i>>2] = $sub256$i;
-        $cmp225$i = ($sub256$i|0)>(0);
-        if ($cmp225$i) {
-         $211 = $sub256$i;$a$1549$i = $a$2$ph$i;$z$1548$i = $z$2$i$lcssa;
-        } else {
-         $$pr477$i = $sub256$i;$a$1$lcssa$i = $a$2$ph$i;$z$1$lcssa$i = $z$2$i$lcssa;
-         break;
-        }
-       }
-      } else {
-       $$pr477$i = $$pr$i;$a$1$lcssa$i = $arraydecay208$add$ptr213$i;$z$1$lcssa$i = $incdec$ptr217$i$lcssa;
-      }
-      $cmp259$537$i = ($$pr477$i|0)<(0);
-      if ($cmp259$537$i) {
-       $add273$i = (($$p$i) + 25)|0;
-       $div274$i = (($add273$i|0) / 9)&-1;
-       $add275$i = (($div274$i) + 1)|0;
-       $cmp299$i = ($or$i$241|0)==(102);
-       $223 = $$pr477$i;$a$3539$i = $a$1$lcssa$i;$z$3538$i = $z$1$lcssa$i;
-       while(1) {
-        $sub264$i = (0 - ($223))|0;
-        $cmp265$i = ($sub264$i|0)>(9);
-        $cond271$i = $cmp265$i ? 9 : $sub264$i;
-        $cmp277$533$i = ($a$3539$i>>>0)<($z$3538$i>>>0);
-        do {
-         if ($cmp277$533$i) {
-          $shl280$i = 1 << $cond271$i;
-          $sub281$i = (($shl280$i) + -1)|0;
-          $shr285$i = 1000000000 >>> $cond271$i;
-          $carry262$0535$i = 0;$d$1534$i = $a$3539$i;
-          while(1) {
-           $225 = HEAP32[$d$1534$i>>2]|0;
-           $and282$i = $225 & $sub281$i;
-           $shr283$i = $225 >>> $cond271$i;
-           $add284$i = (($shr283$i) + ($carry262$0535$i))|0;
-           HEAP32[$d$1534$i>>2] = $add284$i;
-           $mul286$i = Math_imul($and282$i, $shr285$i)|0;
-           $incdec$ptr288$i = ((($d$1534$i)) + 4|0);
-           $cmp277$i = ($incdec$ptr288$i>>>0)<($z$3538$i>>>0);
-           if ($cmp277$i) {
-            $carry262$0535$i = $mul286$i;$d$1534$i = $incdec$ptr288$i;
-           } else {
-            $mul286$i$lcssa = $mul286$i;
-            break;
-           }
-          }
-          $226 = HEAP32[$a$3539$i>>2]|0;
-          $tobool290$i = ($226|0)==(0);
-          $incdec$ptr292$i = ((($a$3539$i)) + 4|0);
-          $incdec$ptr292$a$3$i = $tobool290$i ? $incdec$ptr292$i : $a$3539$i;
-          $tobool294$i = ($mul286$i$lcssa|0)==(0);
-          if ($tobool294$i) {
-           $incdec$ptr292$a$3573$i = $incdec$ptr292$a$3$i;$z$4$i = $z$3538$i;
-           break;
-          }
-          $incdec$ptr296$i = ((($z$3538$i)) + 4|0);
-          HEAP32[$z$3538$i>>2] = $mul286$i$lcssa;
-          $incdec$ptr292$a$3573$i = $incdec$ptr292$a$3$i;$z$4$i = $incdec$ptr296$i;
-         } else {
-          $224 = HEAP32[$a$3539$i>>2]|0;
-          $tobool290$569$i = ($224|0)==(0);
-          $incdec$ptr292$570$i = ((($a$3539$i)) + 4|0);
-          $incdec$ptr292$a$3$571$i = $tobool290$569$i ? $incdec$ptr292$570$i : $a$3539$i;
-          $incdec$ptr292$a$3573$i = $incdec$ptr292$a$3$571$i;$z$4$i = $z$3538$i;
-         }
-        } while(0);
-        $cond304$i = $cmp299$i ? $arraydecay208$add$ptr213$i : $incdec$ptr292$a$3573$i;
-        $sub$ptr$lhs$cast305$i = $z$4$i;
-        $sub$ptr$rhs$cast306$i = $cond304$i;
-        $sub$ptr$sub307$i = (($sub$ptr$lhs$cast305$i) - ($sub$ptr$rhs$cast306$i))|0;
-        $sub$ptr$div$i = $sub$ptr$sub307$i >> 2;
-        $cmp308$i = ($sub$ptr$div$i|0)>($add275$i|0);
-        $add$ptr311$i = (($cond304$i) + ($add275$i<<2)|0);
-        $add$ptr311$z$4$i = $cmp308$i ? $add$ptr311$i : $z$4$i;
-        $227 = HEAP32[$e2$i>>2]|0;
-        $add313$i = (($227) + ($cond271$i))|0;
-        HEAP32[$e2$i>>2] = $add313$i;
-        $cmp259$i = ($add313$i|0)<(0);
-        if ($cmp259$i) {
-         $223 = $add313$i;$a$3539$i = $incdec$ptr292$a$3573$i;$z$3538$i = $add$ptr311$z$4$i;
-        } else {
-         $a$3$lcssa$i = $incdec$ptr292$a$3573$i;$z$3$lcssa$i = $add$ptr311$z$4$i;
-         break;
-        }
-       }
-      } else {
-       $a$3$lcssa$i = $a$1$lcssa$i;$z$3$lcssa$i = $z$1$lcssa$i;
-      }
-      $cmp315$i = ($a$3$lcssa$i>>>0)<($z$3$lcssa$i>>>0);
-      do {
-       if ($cmp315$i) {
-        $sub$ptr$rhs$cast319$i = $a$3$lcssa$i;
-        $sub$ptr$sub320$i = (($sub$ptr$rhs$cast345$i) - ($sub$ptr$rhs$cast319$i))|0;
-        $sub$ptr$div321$i = $sub$ptr$sub320$i >> 2;
-        $mul322$i = ($sub$ptr$div321$i*9)|0;
-        $228 = HEAP32[$a$3$lcssa$i>>2]|0;
-        $cmp324$529$i = ($228>>>0)<(10);
-        if ($cmp324$529$i) {
-         $e$1$i = $mul322$i;
-         break;
-        } else {
-         $e$0531$i = $mul322$i;$i$0530$i = 10;
-        }
-        while(1) {
-         $mul328$i = ($i$0530$i*10)|0;
-         $inc$i = (($e$0531$i) + 1)|0;
-         $cmp324$i = ($228>>>0)<($mul328$i>>>0);
-         if ($cmp324$i) {
-          $e$1$i = $inc$i;
-          break;
-         } else {
-          $e$0531$i = $inc$i;$i$0530$i = $mul328$i;
-         }
-        }
-       } else {
-        $e$1$i = 0;
-       }
-      } while(0);
-      $cmp333$i = ($or$i$241|0)!=(102);
-      $mul335$i = $cmp333$i ? $e$1$i : 0;
-      $sub336$i = (($$p$i) - ($mul335$i))|0;
-      $cmp338$i = ($or$i$241|0)==(103);
-      $tobool341$i = ($$p$i|0)!=(0);
-      $229 = $tobool341$i & $cmp338$i;
-      $land$ext$neg$i = $229 << 31 >> 31;
-      $sub343$i = (($sub336$i) + ($land$ext$neg$i))|0;
-      $sub$ptr$lhs$cast344$i = $z$3$lcssa$i;
-      $sub$ptr$sub346$i = (($sub$ptr$lhs$cast344$i) - ($sub$ptr$rhs$cast345$i))|0;
-      $sub$ptr$div347$i = $sub$ptr$sub346$i >> 2;
-      $230 = ($sub$ptr$div347$i*9)|0;
-      $mul349$i = (($230) + -9)|0;
-      $cmp350$i = ($sub343$i|0)<($mul349$i|0);
-      if ($cmp350$i) {
-       $add$ptr354$i = ((($arraydecay208$add$ptr213$i)) + 4|0);
-       $add355$i = (($sub343$i) + 9216)|0;
-       $div356$i = (($add355$i|0) / 9)&-1;
-       $sub357$i = (($div356$i) + -1024)|0;
-       $add$ptr358$i = (($add$ptr354$i) + ($sub357$i<<2)|0);
-       $rem360$i = (($add355$i|0) % 9)&-1;
-       $j$0$524$i = (($rem360$i) + 1)|0;
-       $cmp363$525$i = ($j$0$524$i|0)<(9);
-       if ($cmp363$525$i) {
-        $i$1526$i = 10;$j$0527$i = $j$0$524$i;
-        while(1) {
-         $mul367$i = ($i$1526$i*10)|0;
-         $j$0$i = (($j$0527$i) + 1)|0;
-         $exitcond$i = ($j$0$i|0)==(9);
-         if ($exitcond$i) {
-          $i$1$lcssa$i = $mul367$i;
-          break;
-         } else {
-          $i$1526$i = $mul367$i;$j$0527$i = $j$0$i;
-         }
-        }
-       } else {
-        $i$1$lcssa$i = 10;
-       }
-       $231 = HEAP32[$add$ptr358$i>>2]|0;
-       $rem370$i = (($231>>>0) % ($i$1$lcssa$i>>>0))&-1;
-       $tobool371$i = ($rem370$i|0)==(0);
-       $add$ptr373$i = ((($add$ptr358$i)) + 4|0);
-       $cmp374$i = ($add$ptr373$i|0)==($z$3$lcssa$i|0);
-       $or$cond395$i = $cmp374$i & $tobool371$i;
-       do {
-        if ($or$cond395$i) {
-         $a$8$i = $a$3$lcssa$i;$d$4$i = $add$ptr358$i;$e$4$i = $e$1$i;
-        } else {
-         $div378$i = (($231>>>0) / ($i$1$lcssa$i>>>0))&-1;
-         $and379$i = $div378$i & 1;
-         $tobool380$i = ($and379$i|0)==(0);
-         $$396$i = $tobool380$i ? 9007199254740992.0 : 9007199254740994.0;
-         $div384$i = (($i$1$lcssa$i|0) / 2)&-1;
-         $cmp385$i = ($rem370$i>>>0)<($div384$i>>>0);
-         if ($cmp385$i) {
-          $small$0$i = 0.5;
-         } else {
-          $cmp390$i = ($rem370$i|0)==($div384$i|0);
-          $or$cond397$i = $cmp374$i & $cmp390$i;
-          $$404$i = $or$cond397$i ? 1.0 : 1.5;
-          $small$0$i = $$404$i;
-         }
-         $tobool400$i = ($pl$0$i|0)==(0);
-         do {
-          if ($tobool400$i) {
-           $round377$1$i = $$396$i;$small$1$i = $small$0$i;
-          } else {
-           $232 = HEAP8[$prefix$0$i>>0]|0;
-           $cmp403$i = ($232<<24>>24)==(45);
-           if (!($cmp403$i)) {
-            $round377$1$i = $$396$i;$small$1$i = $small$0$i;
-            break;
-           }
-           $mul406$i = -$$396$i;
-           $mul407$i = -$small$0$i;
-           $round377$1$i = $mul406$i;$small$1$i = $mul407$i;
-          }
-         } while(0);
-         $sub409$i = (($231) - ($rem370$i))|0;
-         HEAP32[$add$ptr358$i>>2] = $sub409$i;
-         $add410$i = $round377$1$i + $small$1$i;
-         $cmp411$i = $add410$i != $round377$1$i;
-         if (!($cmp411$i)) {
-          $a$8$i = $a$3$lcssa$i;$d$4$i = $add$ptr358$i;$e$4$i = $e$1$i;
-          break;
-         }
-         $add414$i = (($sub409$i) + ($i$1$lcssa$i))|0;
-         HEAP32[$add$ptr358$i>>2] = $add414$i;
-         $cmp416$519$i = ($add414$i>>>0)>(999999999);
-         if ($cmp416$519$i) {
-          $a$5521$i = $a$3$lcssa$i;$d$2520$i = $add$ptr358$i;
-          while(1) {
-           $incdec$ptr419$i = ((($d$2520$i)) + -4|0);
-           HEAP32[$d$2520$i>>2] = 0;
-           $cmp420$i = ($incdec$ptr419$i>>>0)<($a$5521$i>>>0);
-           if ($cmp420$i) {
-            $incdec$ptr423$i = ((($a$5521$i)) + -4|0);
-            HEAP32[$incdec$ptr423$i>>2] = 0;
-            $a$6$i = $incdec$ptr423$i;
-           } else {
-            $a$6$i = $a$5521$i;
-           }
-           $233 = HEAP32[$incdec$ptr419$i>>2]|0;
-           $inc425$i = (($233) + 1)|0;
-           HEAP32[$incdec$ptr419$i>>2] = $inc425$i;
-           $cmp416$i = ($inc425$i>>>0)>(999999999);
-           if ($cmp416$i) {
-            $a$5521$i = $a$6$i;$d$2520$i = $incdec$ptr419$i;
-           } else {
-            $a$5$lcssa$i = $a$6$i;$d$2$lcssa$i = $incdec$ptr419$i;
-            break;
-           }
-          }
-         } else {
-          $a$5$lcssa$i = $a$3$lcssa$i;$d$2$lcssa$i = $add$ptr358$i;
-         }
-         $sub$ptr$rhs$cast428$i = $a$5$lcssa$i;
-         $sub$ptr$sub429$i = (($sub$ptr$rhs$cast345$i) - ($sub$ptr$rhs$cast428$i))|0;
-         $sub$ptr$div430$i = $sub$ptr$sub429$i >> 2;
-         $mul431$i = ($sub$ptr$div430$i*9)|0;
-         $234 = HEAP32[$a$5$lcssa$i>>2]|0;
-         $cmp433$515$i = ($234>>>0)<(10);
-         if ($cmp433$515$i) {
-          $a$8$i = $a$5$lcssa$i;$d$4$i = $d$2$lcssa$i;$e$4$i = $mul431$i;
-          break;
-         } else {
-          $e$2517$i = $mul431$i;$i$2516$i = 10;
-         }
-         while(1) {
-          $mul437$i = ($i$2516$i*10)|0;
-          $inc438$i = (($e$2517$i) + 1)|0;
-          $cmp433$i = ($234>>>0)<($mul437$i>>>0);
-          if ($cmp433$i) {
-           $a$8$i = $a$5$lcssa$i;$d$4$i = $d$2$lcssa$i;$e$4$i = $inc438$i;
-           break;
-          } else {
-           $e$2517$i = $inc438$i;$i$2516$i = $mul437$i;
-          }
-         }
-        }
-       } while(0);
-       $add$ptr442$i = ((($d$4$i)) + 4|0);
-       $cmp443$i = ($z$3$lcssa$i>>>0)>($add$ptr442$i>>>0);
-       $add$ptr442$z$3$i = $cmp443$i ? $add$ptr442$i : $z$3$lcssa$i;
-       $a$9$ph$i = $a$8$i;$e$5$ph$i = $e$4$i;$z$7$ph$i = $add$ptr442$z$3$i;
-      } else {
-       $a$9$ph$i = $a$3$lcssa$i;$e$5$ph$i = $e$1$i;$z$7$ph$i = $z$3$lcssa$i;
-      }
-      $sub626$le$i = (0 - ($e$5$ph$i))|0;
-      $z$7$i = $z$7$ph$i;
-      while(1) {
-       $cmp450$i = ($z$7$i>>>0)>($a$9$ph$i>>>0);
-       if (!($cmp450$i)) {
-        $cmp450$lcssa$i = 0;$z$7$i$lcssa = $z$7$i;
-        break;
-       }
-       $arrayidx453$i = ((($z$7$i)) + -4|0);
-       $235 = HEAP32[$arrayidx453$i>>2]|0;
-       $lnot455$i = ($235|0)==(0);
-       if ($lnot455$i) {
-        $z$7$i = $arrayidx453$i;
-       } else {
-        $cmp450$lcssa$i = 1;$z$7$i$lcssa = $z$7$i;
-        break;
-       }
-      }
-      do {
-       if ($cmp338$i) {
-        $236 = $tobool341$i&1;
-        $inc468$i = $236 ^ 1;
-        $$p$inc468$i = (($inc468$i) + ($$p$i))|0;
-        $cmp470$i = ($$p$inc468$i|0)>($e$5$ph$i|0);
-        $cmp473$i = ($e$5$ph$i|0)>(-5);
-        $or$cond2$i = $cmp470$i & $cmp473$i;
-        if ($or$cond2$i) {
-         $dec476$i = (($t$0) + -1)|0;
-         $add477$neg$i = (($$p$inc468$i) + -1)|0;
-         $sub478$i = (($add477$neg$i) - ($e$5$ph$i))|0;
-         $p$addr$2$i = $sub478$i;$t$addr$0$i = $dec476$i;
-        } else {
-         $sub480$i = (($t$0) + -2)|0;
-         $dec481$i = (($$p$inc468$i) + -1)|0;
-         $p$addr$2$i = $dec481$i;$t$addr$0$i = $sub480$i;
-        }
-        $and483$i = $fl$1$and219 & 8;
-        $tobool484$i = ($and483$i|0)==(0);
-        if (!($tobool484$i)) {
-         $and610$pre$phi$iZ2D = $and483$i;$p$addr$3$i = $p$addr$2$i;$t$addr$1$i = $t$addr$0$i;
-         break;
-        }
-        do {
-         if ($cmp450$lcssa$i) {
-          $arrayidx489$i = ((($z$7$i$lcssa)) + -4|0);
-          $237 = HEAP32[$arrayidx489$i>>2]|0;
-          $tobool490$i = ($237|0)==(0);
-          if ($tobool490$i) {
-           $j$2$i = 9;
-           break;
-          }
-          $rem494$510$i = (($237>>>0) % 10)&-1;
-          $cmp495$511$i = ($rem494$510$i|0)==(0);
-          if ($cmp495$511$i) {
-           $i$3512$i = 10;$j$1513$i = 0;
-          } else {
-           $j$2$i = 0;
-           break;
-          }
-          while(1) {
-           $mul499$i = ($i$3512$i*10)|0;
-           $inc500$i = (($j$1513$i) + 1)|0;
-           $rem494$i = (($237>>>0) % ($mul499$i>>>0))&-1;
-           $cmp495$i = ($rem494$i|0)==(0);
-           if ($cmp495$i) {
-            $i$3512$i = $mul499$i;$j$1513$i = $inc500$i;
-           } else {
-            $j$2$i = $inc500$i;
-            break;
-           }
-          }
-         } else {
-          $j$2$i = 9;
-         }
-        } while(0);
-        $or504$i = $t$addr$0$i | 32;
-        $cmp505$i = ($or504$i|0)==(102);
-        $sub$ptr$lhs$cast508$i = $z$7$i$lcssa;
-        $sub$ptr$sub510$i = (($sub$ptr$lhs$cast508$i) - ($sub$ptr$rhs$cast345$i))|0;
-        $sub$ptr$div511$i = $sub$ptr$sub510$i >> 2;
-        $238 = ($sub$ptr$div511$i*9)|0;
-        $mul513$i = (($238) + -9)|0;
-        if ($cmp505$i) {
-         $sub514$i = (($mul513$i) - ($j$2$i))|0;
-         $cmp515$i = ($sub514$i|0)<(0);
-         $$sub514$i = $cmp515$i ? 0 : $sub514$i;
-         $cmp528$i = ($p$addr$2$i|0)<($$sub514$i|0);
-         $p$addr$2$$sub514398$i = $cmp528$i ? $p$addr$2$i : $$sub514$i;
-         $and610$pre$phi$iZ2D = 0;$p$addr$3$i = $p$addr$2$$sub514398$i;$t$addr$1$i = $t$addr$0$i;
-         break;
-        } else {
-         $add561$i = (($mul513$i) + ($e$5$ph$i))|0;
-         $sub562$i = (($add561$i) - ($j$2$i))|0;
-         $cmp563$i = ($sub562$i|0)<(0);
-         $$sub562$i = $cmp563$i ? 0 : $sub562$i;
-         $cmp577$i = ($p$addr$2$i|0)<($$sub562$i|0);
-         $p$addr$2$$sub562399$i = $cmp577$i ? $p$addr$2$i : $$sub562$i;
-         $and610$pre$phi$iZ2D = 0;$p$addr$3$i = $p$addr$2$$sub562399$i;$t$addr$1$i = $t$addr$0$i;
-         break;
-        }
-       } else {
-        $$pre567$i = $fl$1$and219 & 8;
-        $and610$pre$phi$iZ2D = $$pre567$i;$p$addr$3$i = $$p$i;$t$addr$1$i = $t$0;
-       }
-      } while(0);
-      $239 = $p$addr$3$i | $and610$pre$phi$iZ2D;
-      $240 = ($239|0)!=(0);
-      $lor$ext$i = $240&1;
-      $or613$i = $t$addr$1$i | 32;
-      $cmp614$i = ($or613$i|0)==(102);
-      if ($cmp614$i) {
-       $cmp617$i = ($e$5$ph$i|0)>(0);
-       $add620$i = $cmp617$i ? $e$5$ph$i : 0;
-       $estr$2$i = 0;$sub$ptr$sub650$pn$i = $add620$i;
-      } else {
-       $cmp623$i = ($e$5$ph$i|0)<(0);
-       $cond629$i = $cmp623$i ? $sub626$le$i : $e$5$ph$i;
-       $241 = ($cond629$i|0)<(0);
-       $242 = $241 << 31 >> 31;
-       $243 = (_fmt_u($cond629$i,$242,$arrayidx$i$236)|0);
-       $sub$ptr$rhs$cast634$504$i = $243;
-       $sub$ptr$sub635$505$i = (($sub$ptr$lhs$cast160$i) - ($sub$ptr$rhs$cast634$504$i))|0;
-       $cmp636$506$i = ($sub$ptr$sub635$505$i|0)<(2);
-       if ($cmp636$506$i) {
-        $estr$1507$i = $243;
-        while(1) {
-         $incdec$ptr639$i = ((($estr$1507$i)) + -1|0);
-         HEAP8[$incdec$ptr639$i>>0] = 48;
-         $sub$ptr$rhs$cast634$i = $incdec$ptr639$i;
-         $sub$ptr$sub635$i = (($sub$ptr$lhs$cast160$i) - ($sub$ptr$rhs$cast634$i))|0;
-         $cmp636$i = ($sub$ptr$sub635$i|0)<(2);
-         if ($cmp636$i) {
-          $estr$1507$i = $incdec$ptr639$i;
-         } else {
-          $estr$1$lcssa$i = $incdec$ptr639$i;
-          break;
-         }
-        }
-       } else {
-        $estr$1$lcssa$i = $243;
-       }
-       $244 = $e$5$ph$i >> 31;
-       $245 = $244 & 2;
-       $246 = (($245) + 43)|0;
-       $conv644$i = $246&255;
-       $incdec$ptr645$i = ((($estr$1$lcssa$i)) + -1|0);
-       HEAP8[$incdec$ptr645$i>>0] = $conv644$i;
-       $conv646$i = $t$addr$1$i&255;
-       $incdec$ptr647$i = ((($estr$1$lcssa$i)) + -2|0);
-       HEAP8[$incdec$ptr647$i>>0] = $conv646$i;
-       $sub$ptr$rhs$cast649$i = $incdec$ptr647$i;
-       $sub$ptr$sub650$i = (($sub$ptr$lhs$cast160$i) - ($sub$ptr$rhs$cast649$i))|0;
-       $estr$2$i = $incdec$ptr647$i;$sub$ptr$sub650$pn$i = $sub$ptr$sub650$i;
-      }
-      $add608$i = (($pl$0$i) + 1)|0;
-      $add612$i = (($add608$i) + ($p$addr$3$i))|0;
-      $l$1$i = (($add612$i) + ($lor$ext$i))|0;
-      $add653$i = (($l$1$i) + ($sub$ptr$sub650$pn$i))|0;
-      _pad($f,32,$w$1,$add653$i,$fl$1$and219);
-      $247 = HEAP32[$f>>2]|0;
-      $and$i$436$i = $247 & 32;
-      $tobool$i$437$i = ($and$i$436$i|0)==(0);
-      if ($tobool$i$437$i) {
-       (___fwritex($prefix$0$i,$pl$0$i,$f)|0);
-      }
-      $xor655$i = $fl$1$and219 ^ 65536;
-      _pad($f,48,$w$1,$add653$i,$xor655$i);
-      do {
-       if ($cmp614$i) {
-        $cmp660$i = ($a$9$ph$i>>>0)>($arraydecay208$add$ptr213$i>>>0);
-        $r$0$a$9$i = $cmp660$i ? $arraydecay208$add$ptr213$i : $a$9$ph$i;
-        $d$5494$i = $r$0$a$9$i;
-        while(1) {
-         $248 = HEAP32[$d$5494$i>>2]|0;
-         $249 = (_fmt_u($248,0,$add$ptr671$i)|0);
-         $cmp673$i = ($d$5494$i|0)==($r$0$a$9$i|0);
-         do {
-          if ($cmp673$i) {
-           $cmp686$i = ($249|0)==($add$ptr671$i|0);
-           if (!($cmp686$i)) {
-            $s668$1$i = $249;
-            break;
-           }
-           HEAP8[$incdec$ptr689$i>>0] = 48;
-           $s668$1$i = $incdec$ptr689$i;
-          } else {
-           $cmp678$491$i = ($249>>>0)>($buf$i>>>0);
-           if ($cmp678$491$i) {
-            $s668$0492$i = $249;
-           } else {
-            $s668$1$i = $249;
-            break;
-           }
-           while(1) {
-            $incdec$ptr681$i = ((($s668$0492$i)) + -1|0);
-            HEAP8[$incdec$ptr681$i>>0] = 48;
-            $cmp678$i = ($incdec$ptr681$i>>>0)>($buf$i>>>0);
-            if ($cmp678$i) {
-             $s668$0492$i = $incdec$ptr681$i;
-            } else {
-             $s668$1$i = $incdec$ptr681$i;
-             break;
-            }
-           }
-          }
-         } while(0);
-         $250 = HEAP32[$f>>2]|0;
-         $and$i$442$i = $250 & 32;
-         $tobool$i$443$i = ($and$i$442$i|0)==(0);
-         if ($tobool$i$443$i) {
-          $sub$ptr$rhs$cast695$i = $s668$1$i;
-          $sub$ptr$sub696$i = (($sub$ptr$lhs$cast694$i) - ($sub$ptr$rhs$cast695$i))|0;
-          (___fwritex($s668$1$i,$sub$ptr$sub696$i,$f)|0);
-         }
-         $incdec$ptr698$i = ((($d$5494$i)) + 4|0);
-         $cmp665$i = ($incdec$ptr698$i>>>0)>($arraydecay208$add$ptr213$i>>>0);
-         if ($cmp665$i) {
-          $incdec$ptr698$i$lcssa = $incdec$ptr698$i;
-          break;
-         } else {
-          $d$5494$i = $incdec$ptr698$i;
-         }
-        }
-        $251 = ($239|0)==(0);
-        do {
-         if (!($251)) {
-          $252 = HEAP32[$f>>2]|0;
-          $and$i$448$i = $252 & 32;
-          $tobool$i$449$i = ($and$i$448$i|0)==(0);
-          if (!($tobool$i$449$i)) {
-           break;
-          }
-          (___fwritex(4143,1,$f)|0);
-         }
-        } while(0);
-        $cmp707$486$i = ($incdec$ptr698$i$lcssa>>>0)<($z$7$i$lcssa>>>0);
-        $cmp710$487$i = ($p$addr$3$i|0)>(0);
-        $253 = $cmp710$487$i & $cmp707$486$i;
-        if ($253) {
-         $d$6488$i = $incdec$ptr698$i$lcssa;$p$addr$4489$i = $p$addr$3$i;
-         while(1) {
-          $254 = HEAP32[$d$6488$i>>2]|0;
-          $255 = (_fmt_u($254,0,$add$ptr671$i)|0);
-          $cmp722$483$i = ($255>>>0)>($buf$i>>>0);
-          if ($cmp722$483$i) {
-           $s715$0484$i = $255;
-           while(1) {
-            $incdec$ptr725$i = ((($s715$0484$i)) + -1|0);
-            HEAP8[$incdec$ptr725$i>>0] = 48;
-            $cmp722$i = ($incdec$ptr725$i>>>0)>($buf$i>>>0);
-            if ($cmp722$i) {
-             $s715$0484$i = $incdec$ptr725$i;
-            } else {
-             $s715$0$lcssa$i = $incdec$ptr725$i;
-             break;
-            }
-           }
-          } else {
-           $s715$0$lcssa$i = $255;
-          }
-          $256 = HEAP32[$f>>2]|0;
-          $and$i$454$i = $256 & 32;
-          $tobool$i$455$i = ($and$i$454$i|0)==(0);
-          if ($tobool$i$455$i) {
-           $cmp727$i = ($p$addr$4489$i|0)>(9);
-           $cond732$i = $cmp727$i ? 9 : $p$addr$4489$i;
-           (___fwritex($s715$0$lcssa$i,$cond732$i,$f)|0);
-          }
-          $incdec$ptr734$i = ((($d$6488$i)) + 4|0);
-          $sub735$i = (($p$addr$4489$i) + -9)|0;
-          $cmp707$i = ($incdec$ptr734$i>>>0)<($z$7$i$lcssa>>>0);
-          $cmp710$i = ($p$addr$4489$i|0)>(9);
-          $257 = $cmp710$i & $cmp707$i;
-          if ($257) {
-           $d$6488$i = $incdec$ptr734$i;$p$addr$4489$i = $sub735$i;
-          } else {
-           $p$addr$4$lcssa$i = $sub735$i;
-           break;
-          }
-         }
-        } else {
-         $p$addr$4$lcssa$i = $p$addr$3$i;
-        }
-        $add737$i = (($p$addr$4$lcssa$i) + 9)|0;
-        _pad($f,48,$add737$i,9,0);
-       } else {
-        $add$ptr742$i = ((($a$9$ph$i)) + 4|0);
-        $z$7$add$ptr742$i = $cmp450$lcssa$i ? $z$7$i$lcssa : $add$ptr742$i;
-        $cmp748$499$i = ($p$addr$3$i|0)>(-1);
-        if ($cmp748$499$i) {
-         $tobool781$i = ($and610$pre$phi$iZ2D|0)==(0);
-         $d$7500$i = $a$9$ph$i;$p$addr$5501$i = $p$addr$3$i;
-         while(1) {
-          $258 = HEAP32[$d$7500$i>>2]|0;
-          $259 = (_fmt_u($258,0,$add$ptr671$i)|0);
-          $cmp760$i = ($259|0)==($add$ptr671$i|0);
-          if ($cmp760$i) {
-           HEAP8[$incdec$ptr689$i>>0] = 48;
-           $s753$0$i = $incdec$ptr689$i;
-          } else {
-           $s753$0$i = $259;
-          }
-          $cmp765$i = ($d$7500$i|0)==($a$9$ph$i|0);
-          do {
-           if ($cmp765$i) {
-            $incdec$ptr776$i = ((($s753$0$i)) + 1|0);
-            $260 = HEAP32[$f>>2]|0;
-            $and$i$460$i = $260 & 32;
-            $tobool$i$461$i = ($and$i$460$i|0)==(0);
-            if ($tobool$i$461$i) {
-             (___fwritex($s753$0$i,1,$f)|0);
-            }
-            $cmp777$i = ($p$addr$5501$i|0)<(1);
-            $or$cond401$i = $tobool781$i & $cmp777$i;
-            if ($or$cond401$i) {
-             $s753$2$i = $incdec$ptr776$i;
-             break;
-            }
-            $261 = HEAP32[$f>>2]|0;
-            $and$i$466$i = $261 & 32;
-            $tobool$i$467$i = ($and$i$466$i|0)==(0);
-            if (!($tobool$i$467$i)) {
-             $s753$2$i = $incdec$ptr776$i;
-             break;
-            }
-            (___fwritex(4143,1,$f)|0);
-            $s753$2$i = $incdec$ptr776$i;
-           } else {
-            $cmp770$495$i = ($s753$0$i>>>0)>($buf$i>>>0);
-            if ($cmp770$495$i) {
-             $s753$1496$i = $s753$0$i;
-            } else {
-             $s753$2$i = $s753$0$i;
-             break;
-            }
-            while(1) {
-             $incdec$ptr773$i = ((($s753$1496$i)) + -1|0);
-             HEAP8[$incdec$ptr773$i>>0] = 48;
-             $cmp770$i = ($incdec$ptr773$i>>>0)>($buf$i>>>0);
-             if ($cmp770$i) {
-              $s753$1496$i = $incdec$ptr773$i;
-             } else {
-              $s753$2$i = $incdec$ptr773$i;
-              break;
-             }
-            }
-           }
-          } while(0);
-          $sub$ptr$rhs$cast788$i = $s753$2$i;
-          $sub$ptr$sub789$i = (($sub$ptr$lhs$cast694$i) - ($sub$ptr$rhs$cast788$i))|0;
-          $262 = HEAP32[$f>>2]|0;
-          $and$i$472$i = $262 & 32;
-          $tobool$i$473$i = ($and$i$472$i|0)==(0);
-          if ($tobool$i$473$i) {
-           $cmp790$i = ($p$addr$5501$i|0)>($sub$ptr$sub789$i|0);
-           $cond800$i = $cmp790$i ? $sub$ptr$sub789$i : $p$addr$5501$i;
-           (___fwritex($s753$2$i,$cond800$i,$f)|0);
-          }
-          $sub806$i = (($p$addr$5501$i) - ($sub$ptr$sub789$i))|0;
-          $incdec$ptr808$i = ((($d$7500$i)) + 4|0);
-          $cmp745$i = ($incdec$ptr808$i>>>0)<($z$7$add$ptr742$i>>>0);
-          $cmp748$i = ($sub806$i|0)>(-1);
-          $263 = $cmp745$i & $cmp748$i;
-          if ($263) {
-           $d$7500$i = $incdec$ptr808$i;$p$addr$5501$i = $sub806$i;
-          } else {
-           $p$addr$5$lcssa$i = $sub806$i;
-           break;
-          }
-         }
-        } else {
-         $p$addr$5$lcssa$i = $p$addr$3$i;
-        }
-        $add810$i = (($p$addr$5$lcssa$i) + 18)|0;
-        _pad($f,48,$add810$i,18,0);
-        $264 = HEAP32[$f>>2]|0;
-        $and$i$i = $264 & 32;
-        $tobool$i$i = ($and$i$i|0)==(0);
-        if (!($tobool$i$i)) {
-         break;
-        }
-        $sub$ptr$rhs$cast812$i = $estr$2$i;
-        $sub$ptr$sub813$i = (($sub$ptr$lhs$cast160$i) - ($sub$ptr$rhs$cast812$i))|0;
-        (___fwritex($estr$2$i,$sub$ptr$sub813$i,$f)|0);
-       }
-      } while(0);
-      $xor816$i = $fl$1$and219 ^ 8192;
-      _pad($f,32,$w$1,$add653$i,$xor816$i);
-      $cmp818$i = ($add653$i|0)<($w$1|0);
-      $w$add653$i = $cmp818$i ? $w$1 : $add653$i;
-      $retval$0$i = $w$add653$i;
-     } else {
-      $and36$i = $t$0 & 32;
-      $tobool37$i = ($and36$i|0)!=(0);
-      $cond$i = $tobool37$i ? 4127 : 4131;
-      $cmp38$i = ($y$addr$0$i != $y$addr$0$i) | (0.0 != 0.0);
-      $cond43$i = $tobool37$i ? 4135 : 4139;
-      $pl$1$i = $cmp38$i ? 0 : $pl$0$i;
-      $s35$0$i = $cmp38$i ? $cond43$i : $cond$i;
-      $add$i$239 = (($pl$1$i) + 3)|0;
-      _pad($f,32,$w$1,$add$i$239,$and219);
-      $193 = HEAP32[$f>>2]|0;
-      $and$i$406$i = $193 & 32;
-      $tobool$i$407$i = ($and$i$406$i|0)==(0);
-      if ($tobool$i$407$i) {
-       (___fwritex($prefix$0$i,$pl$1$i,$f)|0);
-       $$pre$i = HEAP32[$f>>2]|0;
-       $194 = $$pre$i;
-      } else {
-       $194 = $193;
-      }
-      $and$i$412$i = $194 & 32;
-      $tobool$i$413$i = ($and$i$412$i|0)==(0);
-      if ($tobool$i$413$i) {
-       (___fwritex($s35$0$i,3,$f)|0);
-      }
-      $xor$i = $fl$1$and219 ^ 8192;
-      _pad($f,32,$w$1,$add$i$239,$xor$i);
-      $cmp48$i = ($add$i$239|0)<($w$1|0);
-      $cond53$i = $cmp48$i ? $w$1 : $add$i$239;
-      $retval$0$i = $cond53$i;
-     }
-    } while(0);
-    $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $retval$0$i;$l10n$0 = $l10n$3;
-    continue L1;
-    break;
-   }
-   default: {
-    $a$2 = $incdec$ptr169275;$fl$6 = $fl$1$and219;$p$5 = $p$0;$pl$2 = 0;$prefix$2 = 4091;$z$2 = $add$ptr205;
-   }
-   }
-  } while(0);
-  L308: do {
-   if ((label|0) == 64) {
-    label = 0;
-    $90 = $arg;
-    $91 = $90;
-    $92 = HEAP32[$91>>2]|0;
-    $93 = (($90) + 4)|0;
-    $94 = $93;
-    $95 = HEAP32[$94>>2]|0;
-    $and249 = $t$1 & 32;
-    $96 = ($92|0)==(0);
-    $97 = ($95|0)==(0);
-    $98 = $96 & $97;
-    if ($98) {
-     $a$0 = $add$ptr205;$fl$4 = $fl$3;$p$2 = $p$1;$pl$1 = 0;$prefix$1 = 4091;
-     label = 77;
-    } else {
-     $101 = $95;$99 = $92;$s$addr$06$i = $add$ptr205;
-     while(1) {
-      $idxprom$i = $99 & 15;
-      $arrayidx$i = (4075 + ($idxprom$i)|0);
-      $100 = HEAP8[$arrayidx$i>>0]|0;
-      $conv$4$i$211 = $100&255;
-      $or$i = $conv$4$i$211 | $and249;
-      $conv1$i = $or$i&255;
-      $incdec$ptr$i$212 = ((($s$addr$06$i)) + -1|0);
-      HEAP8[$incdec$ptr$i$212>>0] = $conv1$i;
-      $102 = (_bitshift64Lshr(($99|0),($101|0),4)|0);
-      $103 = tempRet0;
-      $104 = ($102|0)==(0);
-      $105 = ($103|0)==(0);
-      $106 = $104 & $105;
-      if ($106) {
-       $incdec$ptr$i$212$lcssa = $incdec$ptr$i$212;
-       break;
-      } else {
-       $101 = $103;$99 = $102;$s$addr$06$i = $incdec$ptr$i$212;
-      }
-     }
-     $107 = $arg;
-     $108 = $107;
-     $109 = HEAP32[$108>>2]|0;
-     $110 = (($107) + 4)|0;
-     $111 = $110;
-     $112 = HEAP32[$111>>2]|0;
-     $113 = ($109|0)==(0);
-     $114 = ($112|0)==(0);
-     $115 = $113 & $114;
-     $and254 = $fl$3 & 8;
-     $tobool255 = ($and254|0)==(0);
-     $or$cond193 = $tobool255 | $115;
-     if ($or$cond193) {
-      $a$0 = $incdec$ptr$i$212$lcssa;$fl$4 = $fl$3;$p$2 = $p$1;$pl$1 = 0;$prefix$1 = 4091;
-      label = 77;
-     } else {
-      $shr = $t$1 >> 4;
-      $add$ptr257 = (4091 + ($shr)|0);
-      $a$0 = $incdec$ptr$i$212$lcssa;$fl$4 = $fl$3;$p$2 = $p$1;$pl$1 = 2;$prefix$1 = $add$ptr257;
-      label = 77;
-     }
-    }
-   }
-   else if ((label|0) == 76) {
-    label = 0;
-    $150 = (_fmt_u($148,$149,$add$ptr205)|0);
-    $a$0 = $150;$fl$4 = $fl$1$and219;$p$2 = $p$0;$pl$1 = $pl$0;$prefix$1 = $prefix$0;
-    label = 77;
-   }
-   else if ((label|0) == 82) {
-    label = 0;
-    $call356 = (_memchr($a$1,0,$p$0)|0);
-    $tobool357 = ($call356|0)==(0|0);
-    $sub$ptr$lhs$cast361 = $call356;
-    $sub$ptr$rhs$cast362 = $a$1;
-    $sub$ptr$sub363 = (($sub$ptr$lhs$cast361) - ($sub$ptr$rhs$cast362))|0;
-    $add$ptr359 = (($a$1) + ($p$0)|0);
-    $z$1 = $tobool357 ? $add$ptr359 : $call356;
-    $p$3 = $tobool357 ? $p$0 : $sub$ptr$sub363;
-    $a$2 = $a$1;$fl$6 = $and219;$p$5 = $p$3;$pl$2 = 0;$prefix$2 = 4091;$z$2 = $z$1;
-   }
-   else if ((label|0) == 86) {
-    label = 0;
-    $176 = HEAP32[$arg>>2]|0;
-    $i$0316 = 0;$l$1315 = 0;$ws$0317 = $176;
-    while(1) {
-     $177 = HEAP32[$ws$0317>>2]|0;
-     $tobool380 = ($177|0)==(0);
-     if ($tobool380) {
-      $i$0$lcssa = $i$0316;$l$2 = $l$1315;
-      break;
-     }
-     $call384 = (_wctomb($mb,$177)|0);
-     $cmp385 = ($call384|0)<(0);
-     $sub389 = (($p$4365) - ($i$0316))|0;
-     $cmp390 = ($call384>>>0)>($sub389>>>0);
-     $or$cond195 = $cmp385 | $cmp390;
-     if ($or$cond195) {
-      $i$0$lcssa = $i$0316;$l$2 = $call384;
-      break;
-     }
-     $incdec$ptr383 = ((($ws$0317)) + 4|0);
-     $add395 = (($call384) + ($i$0316))|0;
-     $cmp377 = ($p$4365>>>0)>($add395>>>0);
-     if ($cmp377) {
-      $i$0316 = $add395;$l$1315 = $call384;$ws$0317 = $incdec$ptr383;
-     } else {
-      $i$0$lcssa = $add395;$l$2 = $call384;
-      break;
-     }
-    }
-    $cmp397 = ($l$2|0)<(0);
-    if ($cmp397) {
-     $retval$0 = -1;
-     break L1;
-    }
-    _pad($f,32,$w$1,$i$0$lcssa,$fl$1$and219);
-    $cmp404$324 = ($i$0$lcssa|0)==(0);
-    if ($cmp404$324) {
-     $i$0$lcssa368 = 0;
-     label = 98;
-    } else {
-     $178 = HEAP32[$arg>>2]|0;
-     $i$1325 = 0;$ws$1326 = $178;
-     while(1) {
-      $179 = HEAP32[$ws$1326>>2]|0;
-      $tobool407 = ($179|0)==(0);
-      if ($tobool407) {
-       $i$0$lcssa368 = $i$0$lcssa;
-       label = 98;
-       break L308;
-      }
-      $incdec$ptr410 = ((($ws$1326)) + 4|0);
-      $call411 = (_wctomb($mb,$179)|0);
-      $add412 = (($call411) + ($i$1325))|0;
-      $cmp413 = ($add412|0)>($i$0$lcssa|0);
-      if ($cmp413) {
-       $i$0$lcssa368 = $i$0$lcssa;
-       label = 98;
-       break L308;
-      }
-      $180 = HEAP32[$f>>2]|0;
-      $and$i$231 = $180 & 32;
-      $tobool$i$232 = ($and$i$231|0)==(0);
-      if ($tobool$i$232) {
-       (___fwritex($mb,$call411,$f)|0);
-      }
-      $cmp404 = ($add412>>>0)<($i$0$lcssa>>>0);
-      if ($cmp404) {
-       $i$1325 = $add412;$ws$1326 = $incdec$ptr410;
-      } else {
-       $i$0$lcssa368 = $i$0$lcssa;
-       label = 98;
-       break;
-      }
-     }
-    }
-   }
-  } while(0);
-  if ((label|0) == 98) {
-   label = 0;
-   $xor = $fl$1$and219 ^ 8192;
-   _pad($f,32,$w$1,$i$0$lcssa368,$xor);
-   $cmp421 = ($w$1|0)>($i$0$lcssa368|0);
-   $cond426 = $cmp421 ? $w$1 : $i$0$lcssa368;
-   $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $cond426;$l10n$0 = $l10n$3;
-   continue;
-  }
-  if ((label|0) == 77) {
-   label = 0;
-   $cmp306 = ($p$2|0)>(-1);
-   $and309 = $fl$4 & -65537;
-   $and309$fl$4 = $cmp306 ? $and309 : $fl$4;
-   $151 = $arg;
-   $152 = $151;
-   $153 = HEAP32[$152>>2]|0;
-   $154 = (($151) + 4)|0;
-   $155 = $154;
-   $156 = HEAP32[$155>>2]|0;
-   $157 = ($153|0)!=(0);
-   $158 = ($156|0)!=(0);
-   $159 = $157 | $158;
-   $tobool314 = ($p$2|0)!=(0);
-   $or$cond = $tobool314 | $159;
-   if ($or$cond) {
-    $sub$ptr$rhs$cast318 = $a$0;
-    $sub$ptr$sub319 = (($sub$ptr$lhs$cast317) - ($sub$ptr$rhs$cast318))|0;
-    $160 = $159&1;
-    $lnot$ext = $160 ^ 1;
-    $add322 = (($lnot$ext) + ($sub$ptr$sub319))|0;
-    $cmp323 = ($p$2|0)>($add322|0);
-    $p$2$add322 = $cmp323 ? $p$2 : $add322;
-    $a$2 = $a$0;$fl$6 = $and309$fl$4;$p$5 = $p$2$add322;$pl$2 = $pl$1;$prefix$2 = $prefix$1;$z$2 = $add$ptr205;
-   } else {
-    $a$2 = $add$ptr205;$fl$6 = $and309$fl$4;$p$5 = 0;$pl$2 = $pl$1;$prefix$2 = $prefix$1;$z$2 = $add$ptr205;
-   }
-  }
-  $sub$ptr$lhs$cast431 = $z$2;
-  $sub$ptr$rhs$cast432 = $a$2;
-  $sub$ptr$sub433 = (($sub$ptr$lhs$cast431) - ($sub$ptr$rhs$cast432))|0;
-  $cmp434 = ($p$5|0)<($sub$ptr$sub433|0);
-  $sub$ptr$sub433$p$5 = $cmp434 ? $sub$ptr$sub433 : $p$5;
-  $add441 = (($pl$2) + ($sub$ptr$sub433$p$5))|0;
-  $cmp442 = ($w$1|0)<($add441|0);
-  $w$2 = $cmp442 ? $add441 : $w$1;
-  _pad($f,32,$w$2,$add441,$fl$6);
-  $265 = HEAP32[$f>>2]|0;
-  $and$i$244 = $265 & 32;
-  $tobool$i$245 = ($and$i$244|0)==(0);
-  if ($tobool$i$245) {
-   (___fwritex($prefix$2,$pl$2,$f)|0);
-  }
-  $xor449 = $fl$6 ^ 65536;
-  _pad($f,48,$w$2,$add441,$xor449);
-  _pad($f,48,$sub$ptr$sub433$p$5,$sub$ptr$sub433,0);
-  $266 = HEAP32[$f>>2]|0;
-  $and$i$216 = $266 & 32;
-  $tobool$i$217 = ($and$i$216|0)==(0);
-  if ($tobool$i$217) {
-   (___fwritex($a$2,$sub$ptr$sub433,$f)|0);
-  }
-  $xor457 = $fl$6 ^ 8192;
-  _pad($f,32,$w$2,$add441,$xor457);
-  $cnt$0 = $cnt$1;$incdec$ptr169275 = $incdec$ptr169$lcssa;$l$0 = $w$2;$l10n$0 = $l10n$3;
- }
- L343: do {
-  if ((label|0) == 242) {
-   $tobool459 = ($f|0)==(0|0);
-   if ($tobool459) {
-    $tobool462 = ($l10n$0$lcssa|0)==(0);
-    if ($tobool462) {
-     $retval$0 = 0;
-    } else {
-     $i$2299 = 1;
-     while(1) {
-      $arrayidx469 = (($nl_type) + ($i$2299<<2)|0);
-      $267 = HEAP32[$arrayidx469>>2]|0;
-      $tobool470 = ($267|0)==(0);
-      if ($tobool470) {
-       $i$2299$lcssa = $i$2299;
-       break;
-      }
-      $add$ptr473 = (($nl_arg) + ($i$2299<<3)|0);
-      _pop_arg_336($add$ptr473,$267,$ap);
-      $inc = (($i$2299) + 1)|0;
-      $cmp466 = ($inc|0)<(10);
-      if ($cmp466) {
-       $i$2299 = $inc;
-      } else {
-       $retval$0 = 1;
-       break L343;
-      }
-     }
-     $cmp478$295 = ($i$2299$lcssa|0)<(10);
-     if ($cmp478$295) {
-      $i$3296 = $i$2299$lcssa;
-      while(1) {
-       $arrayidx481 = (($nl_type) + ($i$3296<<2)|0);
-       $268 = HEAP32[$arrayidx481>>2]|0;
-       $lnot483 = ($268|0)==(0);
-       $inc488 = (($i$3296) + 1)|0;
-       if (!($lnot483)) {
-        $retval$0 = -1;
-        break L343;
-       }
-       $cmp478 = ($inc488|0)<(10);
-       if ($cmp478) {
-        $i$3296 = $inc488;
-       } else {
-        $retval$0 = 1;
-        break;
-       }
-      }
-     } else {
-      $retval$0 = 1;
-     }
-    }
-   } else {
-    $retval$0 = $cnt$1$lcssa;
-   }
-  }
- } while(0);
- STACKTOP = sp;return ($retval$0|0);
-}
-function _pop_arg_336($arg,$type,$ap) {
- $arg = $arg|0;
- $type = $type|0;
- $ap = $ap|0;
- var $0 = 0, $1 = 0, $10 = 0, $100 = 0, $101 = 0, $102 = 0, $103 = 0.0, $104 = 0, $105 = 0, $106 = 0, $107 = 0, $108 = 0, $109 = 0, $11 = 0, $110 = 0.0, $12 = 0, $13 = 0, $14 = 0, $15 = 0, $16 = 0;
- var $17 = 0, $18 = 0, $19 = 0, $2 = 0, $20 = 0, $21 = 0, $22 = 0, $23 = 0, $24 = 0, $25 = 0, $26 = 0, $27 = 0, $28 = 0, $29 = 0, $3 = 0, $30 = 0, $31 = 0, $32 = 0, $33 = 0, $34 = 0;
- var $35 = 0, $36 = 0, $37 = 0, $38 = 0, $39 = 0, $4 = 0, $40 = 0, $41 = 0, $42 = 0, $43 = 0, $44 = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, $49 = 0, $5 = 0, $50 = 0, $51 = 0, $52 = 0;
- var $53 = 0, $54 = 0, $55 = 0, $56 = 0, $57 = 0, $58 = 0, $59 = 0, $6 = 0, $60 = 0, $61 = 0, $62 = 0, $63 = 0, $64 = 0, $65 = 0, $66 = 0, $67 = 0, $68 = 0, $69 = 0, $7 = 0, $70 = 0;
- var $71 = 0, $72 = 0, $73 = 0, $74 = 0, $75 = 0, $76 = 0, $77 = 0, $78 = 0, $79 = 0, $8 = 0, $80 = 0, $81 = 0, $82 = 0, $83 = 0, $84 = 0, $85 = 0, $86 = 0, $87 = 0, $88 = 0, $89 = 0;
- var $9 = 0, $90 = 0, $91 = 0, $92 = 0, $93 = 0, $94 = 0, $95 = 0, $96 = 0, $97 = 0, $98 = 0, $99 = 0, $arglist_current = 0, $arglist_current11 = 0, $arglist_current14 = 0, $arglist_current17 = 0, $arglist_current2 = 0, $arglist_current20 = 0, $arglist_current23 = 0, $arglist_current26 = 0, $arglist_current5 = 0;
- var $arglist_current8 = 0, $arglist_next = 0, $arglist_next12 = 0, $arglist_next15 = 0, $arglist_next18 = 0, $arglist_next21 = 0, $arglist_next24 = 0, $arglist_next27 = 0, $arglist_next3 = 0, $arglist_next6 = 0, $arglist_next9 = 0, $cmp = 0, $conv12 = 0, $conv17$mask = 0, $conv22 = 0, $conv27$mask = 0, $expanded = 0, $expanded28 = 0, $expanded30 = 0, $expanded31 = 0;
- var $expanded32 = 0, $expanded34 = 0, $expanded35 = 0, $expanded37 = 0, $expanded38 = 0, $expanded39 = 0, $expanded41 = 0, $expanded42 = 0, $expanded44 = 0, $expanded45 = 0, $expanded46 = 0, $expanded48 = 0, $expanded49 = 0, $expanded51 = 0, $expanded52 = 0, $expanded53 = 0, $expanded55 = 0, $expanded56 = 0, $expanded58 = 0, $expanded59 = 0;
- var $expanded60 = 0, $expanded62 = 0, $expanded63 = 0, $expanded65 = 0, $expanded66 = 0, $expanded67 = 0, $expanded69 = 0, $expanded70 = 0, $expanded72 = 0, $expanded73 = 0, $expanded74 = 0, $expanded76 = 0, $expanded77 = 0, $expanded79 = 0, $expanded80 = 0, $expanded81 = 0, $expanded83 = 0, $expanded84 = 0, $expanded86 = 0, $expanded87 = 0;
- var $expanded88 = 0, $expanded90 = 0, $expanded91 = 0, $expanded93 = 0, $expanded94 = 0, $expanded95 = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $cmp = ($type>>>0)>(20);
- L1: do {
-  if (!($cmp)) {
-   do {
-    switch ($type|0) {
-    case 9:  {
-     $arglist_current = HEAP32[$ap>>2]|0;
-     $0 = $arglist_current;
-     $1 = ((0) + 4|0);
-     $expanded28 = $1;
-     $expanded = (($expanded28) - 1)|0;
-     $2 = (($0) + ($expanded))|0;
-     $3 = ((0) + 4|0);
-     $expanded32 = $3;
-     $expanded31 = (($expanded32) - 1)|0;
-     $expanded30 = $expanded31 ^ -1;
-     $4 = $2 & $expanded30;
-     $5 = $4;
-     $6 = HEAP32[$5>>2]|0;
-     $arglist_next = ((($5)) + 4|0);
-     HEAP32[$ap>>2] = $arglist_next;
-     HEAP32[$arg>>2] = $6;
-     break L1;
-     break;
-    }
-    case 10:  {
-     $arglist_current2 = HEAP32[$ap>>2]|0;
-     $7 = $arglist_current2;
-     $8 = ((0) + 4|0);
-     $expanded35 = $8;
-     $expanded34 = (($expanded35) - 1)|0;
-     $9 = (($7) + ($expanded34))|0;
-     $10 = ((0) + 4|0);
-     $expanded39 = $10;
-     $expanded38 = (($expanded39) - 1)|0;
-     $expanded37 = $expanded38 ^ -1;
-     $11 = $9 & $expanded37;
-     $12 = $11;
-     $13 = HEAP32[$12>>2]|0;
-     $arglist_next3 = ((($12)) + 4|0);
-     HEAP32[$ap>>2] = $arglist_next3;
-     $14 = ($13|0)<(0);
-     $15 = $14 << 31 >> 31;
-     $16 = $arg;
-     $17 = $16;
-     HEAP32[$17>>2] = $13;
-     $18 = (($16) + 4)|0;
-     $19 = $18;
-     HEAP32[$19>>2] = $15;
-     break L1;
-     break;
-    }
-    case 11:  {
-     $arglist_current5 = HEAP32[$ap>>2]|0;
-     $20 = $arglist_current5;
-     $21 = ((0) + 4|0);
-     $expanded42 = $21;
-     $expanded41 = (($expanded42) - 1)|0;
-     $22 = (($20) + ($expanded41))|0;
-     $23 = ((0) + 4|0);
-     $expanded46 = $23;
-     $expanded45 = (($expanded46) - 1)|0;
-     $expanded44 = $expanded45 ^ -1;
-     $24 = $22 & $expanded44;
-     $25 = $24;
-     $26 = HEAP32[$25>>2]|0;
-     $arglist_next6 = ((($25)) + 4|0);
-     HEAP32[$ap>>2] = $arglist_next6;
-     $27 = $arg;
-     $28 = $27;
-     HEAP32[$28>>2] = $26;
-     $29 = (($27) + 4)|0;
-     $30 = $29;
-     HEAP32[$30>>2] = 0;
-     break L1;
-     break;
-    }
-    case 12:  {
-     $arglist_current8 = HEAP32[$ap>>2]|0;
-     $31 = $arglist_current8;
-     $32 = ((0) + 8|0);
-     $expanded49 = $32;
-     $expanded48 = (($expanded49) - 1)|0;
-     $33 = (($31) + ($expanded48))|0;
-     $34 = ((0) + 8|0);
-     $expanded53 = $34;
-     $expanded52 = (($expanded53) - 1)|0;
-     $expanded51 = $expanded52 ^ -1;
-     $35 = $33 & $expanded51;
-     $36 = $35;
-     $37 = $36;
-     $38 = $37;
-     $39 = HEAP32[$38>>2]|0;
-     $40 = (($37) + 4)|0;
-     $41 = $40;
-     $42 = HEAP32[$41>>2]|0;
-     $arglist_next9 = ((($36)) + 8|0);
-     HEAP32[$ap>>2] = $arglist_next9;
-     $43 = $arg;
-     $44 = $43;
-     HEAP32[$44>>2] = $39;
-     $45 = (($43) + 4)|0;
-     $46 = $45;
-     HEAP32[$46>>2] = $42;
-     break L1;
-     break;
-    }
-    case 13:  {
-     $arglist_current11 = HEAP32[$ap>>2]|0;
-     $47 = $arglist_current11;
-     $48 = ((0) + 4|0);
-     $expanded56 = $48;
-     $expanded55 = (($expanded56) - 1)|0;
-     $49 = (($47) + ($expanded55))|0;
-     $50 = ((0) + 4|0);
-     $expanded60 = $50;
-     $expanded59 = (($expanded60) - 1)|0;
-     $expanded58 = $expanded59 ^ -1;
-     $51 = $49 & $expanded58;
-     $52 = $51;
-     $53 = HEAP32[$52>>2]|0;
-     $arglist_next12 = ((($52)) + 4|0);
-     HEAP32[$ap>>2] = $arglist_next12;
-     $conv12 = $53&65535;
-     $54 = $conv12 << 16 >> 16;
-     $55 = ($54|0)<(0);
-     $56 = $55 << 31 >> 31;
-     $57 = $arg;
-     $58 = $57;
-     HEAP32[$58>>2] = $54;
-     $59 = (($57) + 4)|0;
-     $60 = $59;
-     HEAP32[$60>>2] = $56;
-     break L1;
-     break;
-    }
-    case 14:  {
-     $arglist_current14 = HEAP32[$ap>>2]|0;
-     $61 = $arglist_current14;
-     $62 = ((0) + 4|0);
-     $expanded63 = $62;
-     $expanded62 = (($expanded63) - 1)|0;
-     $63 = (($61) + ($expanded62))|0;
-     $64 = ((0) + 4|0);
-     $expanded67 = $64;
-     $expanded66 = (($expanded67) - 1)|0;
-     $expanded65 = $expanded66 ^ -1;
-     $65 = $63 & $expanded65;
-     $66 = $65;
-     $67 = HEAP32[$66>>2]|0;
-     $arglist_next15 = ((($66)) + 4|0);
-     HEAP32[$ap>>2] = $arglist_next15;
-     $conv17$mask = $67 & 65535;
-     $68 = $arg;
-     $69 = $68;
-     HEAP32[$69>>2] = $conv17$mask;
-     $70 = (($68) + 4)|0;
-     $71 = $70;
-     HEAP32[$71>>2] = 0;
-     break L1;
-     break;
-    }
-    case 15:  {
-     $arglist_current17 = HEAP32[$ap>>2]|0;
-     $72 = $arglist_current17;
-     $73 = ((0) + 4|0);
-     $expanded70 = $73;
-     $expanded69 = (($expanded70) - 1)|0;
-     $74 = (($72) + ($expanded69))|0;
-     $75 = ((0) + 4|0);
-     $expanded74 = $75;
-     $expanded73 = (($expanded74) - 1)|0;
-     $expanded72 = $expanded73 ^ -1;
-     $76 = $74 & $expanded72;
-     $77 = $76;
-     $78 = HEAP32[$77>>2]|0;
-     $arglist_next18 = ((($77)) + 4|0);
-     HEAP32[$ap>>2] = $arglist_next18;
-     $conv22 = $78&255;
-     $79 = $conv22 << 24 >> 24;
-     $80 = ($79|0)<(0);
-     $81 = $80 << 31 >> 31;
-     $82 = $arg;
-     $83 = $82;
-     HEAP32[$83>>2] = $79;
-     $84 = (($82) + 4)|0;
-     $85 = $84;
-     HEAP32[$85>>2] = $81;
-     break L1;
-     break;
-    }
-    case 16:  {
-     $arglist_current20 = HEAP32[$ap>>2]|0;
-     $86 = $arglist_current20;
-     $87 = ((0) + 4|0);
-     $expanded77 = $87;
-     $expanded76 = (($expanded77) - 1)|0;
-     $88 = (($86) + ($expanded76))|0;
-     $89 = ((0) + 4|0);
-     $expanded81 = $89;
-     $expanded80 = (($expanded81) - 1)|0;
-     $expanded79 = $expanded80 ^ -1;
-     $90 = $88 & $expanded79;
-     $91 = $90;
-     $92 = HEAP32[$91>>2]|0;
-     $arglist_next21 = ((($91)) + 4|0);
-     HEAP32[$ap>>2] = $arglist_next21;
-     $conv27$mask = $92 & 255;
-     $93 = $arg;
-     $94 = $93;
-     HEAP32[$94>>2] = $conv27$mask;
-     $95 = (($93) + 4)|0;
-     $96 = $95;
-     HEAP32[$96>>2] = 0;
-     break L1;
-     break;
-    }
-    case 17:  {
-     $arglist_current23 = HEAP32[$ap>>2]|0;
-     $97 = $arglist_current23;
-     $98 = ((0) + 8|0);
-     $expanded84 = $98;
-     $expanded83 = (($expanded84) - 1)|0;
-     $99 = (($97) + ($expanded83))|0;
-     $100 = ((0) + 8|0);
-     $expanded88 = $100;
-     $expanded87 = (($expanded88) - 1)|0;
-     $expanded86 = $expanded87 ^ -1;
-     $101 = $99 & $expanded86;
-     $102 = $101;
-     $103 = +HEAPF64[$102>>3];
-     $arglist_next24 = ((($102)) + 8|0);
-     HEAP32[$ap>>2] = $arglist_next24;
-     HEAPF64[$arg>>3] = $103;
-     break L1;
-     break;
-    }
-    case 18:  {
-     $arglist_current26 = HEAP32[$ap>>2]|0;
-     $104 = $arglist_current26;
-     $105 = ((0) + 8|0);
-     $expanded91 = $105;
-     $expanded90 = (($expanded91) - 1)|0;
-     $106 = (($104) + ($expanded90))|0;
-     $107 = ((0) + 8|0);
-     $expanded95 = $107;
-     $expanded94 = (($expanded95) - 1)|0;
-     $expanded93 = $expanded94 ^ -1;
-     $108 = $106 & $expanded93;
-     $109 = $108;
-     $110 = +HEAPF64[$109>>3];
-     $arglist_next27 = ((($109)) + 8|0);
-     HEAP32[$ap>>2] = $arglist_next27;
-     HEAPF64[$arg>>3] = $110;
-     break L1;
-     break;
-    }
-    default: {
-     break L1;
-    }
-    }
-   } while(0);
-  }
- } while(0);
- return;
-}
-function _fmt_u($0,$1,$s) {
- $0 = $0|0;
- $1 = $1|0;
- $s = $s|0;
- var $10 = 0, $11 = 0, $12 = 0, $13 = 0, $14 = 0, $15 = 0, $16 = 0, $17 = 0, $18 = 0, $19 = 0, $2 = 0, $20 = 0, $21 = 0, $22 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0, $8 = 0;
- var $9 = 0, $add5 = 0, $conv6 = 0, $div9 = 0, $incdec$ptr = 0, $incdec$ptr$lcssa = 0, $incdec$ptr7 = 0, $rem4 = 0, $s$addr$0$lcssa = 0, $s$addr$013 = 0, $s$addr$1$lcssa = 0, $s$addr$19 = 0, $tobool$8 = 0, $x$addr$0$lcssa$off0 = 0, $y$010 = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $2 = ($1>>>0)>(0);
- $3 = ($0>>>0)>(4294967295);
- $4 = ($1|0)==(0);
- $5 = $4 & $3;
- $6 = $2 | $5;
- if ($6) {
-  $7 = $0;$8 = $1;$s$addr$013 = $s;
-  while(1) {
-   $9 = (___uremdi3(($7|0),($8|0),10,0)|0);
-   $10 = tempRet0;
-   $11 = $9 | 48;
-   $12 = $11&255;
-   $incdec$ptr = ((($s$addr$013)) + -1|0);
-   HEAP8[$incdec$ptr>>0] = $12;
-   $13 = (___udivdi3(($7|0),($8|0),10,0)|0);
-   $14 = tempRet0;
-   $15 = ($8>>>0)>(9);
-   $16 = ($7>>>0)>(4294967295);
-   $17 = ($8|0)==(9);
-   $18 = $17 & $16;
-   $19 = $15 | $18;
-   if ($19) {
-    $7 = $13;$8 = $14;$s$addr$013 = $incdec$ptr;
-   } else {
-    $21 = $13;$22 = $14;$incdec$ptr$lcssa = $incdec$ptr;
-    break;
-   }
-  }
-  $s$addr$0$lcssa = $incdec$ptr$lcssa;$x$addr$0$lcssa$off0 = $21;
- } else {
-  $s$addr$0$lcssa = $s;$x$addr$0$lcssa$off0 = $0;
- }
- $tobool$8 = ($x$addr$0$lcssa$off0|0)==(0);
- if ($tobool$8) {
-  $s$addr$1$lcssa = $s$addr$0$lcssa;
- } else {
-  $s$addr$19 = $s$addr$0$lcssa;$y$010 = $x$addr$0$lcssa$off0;
-  while(1) {
-   $rem4 = (($y$010>>>0) % 10)&-1;
-   $add5 = $rem4 | 48;
-   $conv6 = $add5&255;
-   $incdec$ptr7 = ((($s$addr$19)) + -1|0);
-   HEAP8[$incdec$ptr7>>0] = $conv6;
-   $div9 = (($y$010>>>0) / 10)&-1;
-   $20 = ($y$010>>>0)<(10);
-   if ($20) {
-    $s$addr$1$lcssa = $incdec$ptr7;
-    break;
-   } else {
-    $s$addr$19 = $incdec$ptr7;$y$010 = $div9;
-   }
-  }
- }
- return ($s$addr$1$lcssa|0);
-}
-function _pad($f,$c,$w,$l,$fl) {
- $f = $f|0;
- $c = $c|0;
- $w = $w|0;
- $l = $l|0;
- $fl = $fl|0;
- var $$pre = 0, $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $and = 0, $and$i = 0, $and$i$15 = 0, $cmp = 0, $cmp1 = 0, $cmp3 = 0, $cmp3$14 = 0, $cond = 0, $l$addr$0$lcssa21 = 0, $l$addr$017 = 0, $or$cond = 0, $pad = 0, $sub = 0, $sub5 = 0;
- var $tobool = 0, $tobool$i = 0, $tobool$i$16 = 0, $tobool$i18 = 0, label = 0, sp = 0;
- sp = STACKTOP;
- STACKTOP = STACKTOP + 256|0; if ((STACKTOP|0) >= (STACK_MAX|0)) abort();
- $pad = sp;
- $and = $fl & 73728;
- $tobool = ($and|0)==(0);
- $cmp = ($w|0)>($l|0);
- $or$cond = $cmp & $tobool;
- do {
-  if ($or$cond) {
-   $sub = (($w) - ($l))|0;
-   $cmp1 = ($sub>>>0)>(256);
-   $cond = $cmp1 ? 256 : $sub;
-   _memset(($pad|0),($c|0),($cond|0))|0;
-   $cmp3$14 = ($sub>>>0)>(255);
-   $0 = HEAP32[$f>>2]|0;
-   $and$i$15 = $0 & 32;
-   $tobool$i$16 = ($and$i$15|0)==(0);
-   if ($cmp3$14) {
-    $1 = (($w) - ($l))|0;
-    $4 = $0;$l$addr$017 = $sub;$tobool$i18 = $tobool$i$16;
-    while(1) {
-     if ($tobool$i18) {
-      (___fwritex($pad,256,$f)|0);
-      $$pre = HEAP32[$f>>2]|0;
-      $2 = $$pre;
-     } else {
-      $2 = $4;
-     }
-     $sub5 = (($l$addr$017) + -256)|0;
-     $cmp3 = ($sub5>>>0)>(255);
-     $and$i = $2 & 32;
-     $tobool$i = ($and$i|0)==(0);
-     if ($cmp3) {
-      $4 = $2;$l$addr$017 = $sub5;$tobool$i18 = $tobool$i;
-     } else {
-      break;
-     }
-    }
-    $3 = $1 & 255;
-    if ($tobool$i) {
-     $l$addr$0$lcssa21 = $3;
-    } else {
-     break;
-    }
-   } else {
-    if ($tobool$i$16) {
-     $l$addr$0$lcssa21 = $sub;
-    } else {
-     break;
-    }
-   }
-   (___fwritex($pad,$l$addr$0$lcssa21,$f)|0);
-  }
- } while(0);
- STACKTOP = sp;return;
-}
-function _malloc($bytes) {
- $bytes = $bytes|0;
- var $$lcssa = 0, $$lcssa290 = 0, $$pre = 0, $$pre$i = 0, $$pre$i$177 = 0, $$pre$i$56$i = 0, $$pre$i$i = 0, $$pre$phi$i$178Z2D = 0, $$pre$phi$i$57$iZ2D = 0, $$pre$phi$i$iZ2D = 0, $$pre$phi$iZ2D = 0, $$pre$phiZ2D = 0, $$pre241 = 0, $$pre5$i$i = 0, $0 = 0, $1 = 0, $10 = 0, $100 = 0, $101 = 0, $102 = 0;
- var $103 = 0, $104 = 0, $105 = 0, $106 = 0, $107 = 0, $108 = 0, $109 = 0, $11 = 0, $110 = 0, $111 = 0, $112 = 0, $113 = 0, $114 = 0, $115 = 0, $116 = 0, $117 = 0, $118 = 0, $119 = 0, $12 = 0, $120 = 0;
- var $121 = 0, $122 = 0, $123 = 0, $124 = 0, $125 = 0, $126 = 0, $127 = 0, $128 = 0, $129 = 0, $13 = 0, $130 = 0, $131 = 0, $132 = 0, $133 = 0, $134 = 0, $135 = 0, $136 = 0, $137 = 0, $138 = 0, $139 = 0;
- var $14 = 0, $140 = 0, $141 = 0, $142 = 0, $143 = 0, $144 = 0, $145 = 0, $146 = 0, $147 = 0, $148 = 0, $149 = 0, $15 = 0, $150 = 0, $151 = 0, $152 = 0, $153 = 0, $154 = 0, $155 = 0, $156 = 0, $157 = 0;
- var $158 = 0, $159 = 0, $16 = 0, $160 = 0, $161 = 0, $162 = 0, $163 = 0, $164 = 0, $165 = 0, $166 = 0, $167 = 0, $168 = 0, $169 = 0, $17 = 0, $170 = 0, $171 = 0, $172 = 0, $173 = 0, $174 = 0, $175 = 0;
- var $176 = 0, $177 = 0, $178 = 0, $179 = 0, $18 = 0, $180 = 0, $181 = 0, $182 = 0, $183 = 0, $184 = 0, $185 = 0, $186 = 0, $187 = 0, $188 = 0, $189 = 0, $19 = 0, $190 = 0, $191 = 0, $192 = 0, $193 = 0;
- var $194 = 0, $195 = 0, $196 = 0, $197 = 0, $198 = 0, $199 = 0, $2 = 0, $20 = 0, $200 = 0, $201 = 0, $202 = 0, $203 = 0, $204 = 0, $205 = 0, $206 = 0, $207 = 0, $208 = 0, $21 = 0, $22 = 0, $23 = 0;
- var $24 = 0, $25 = 0, $26 = 0, $27 = 0, $28 = 0, $29 = 0, $3 = 0, $30 = 0, $31 = 0, $32 = 0, $33 = 0, $34 = 0, $35 = 0, $36 = 0, $37 = 0, $38 = 0, $39 = 0, $4 = 0, $40 = 0, $41 = 0;
- var $42 = 0, $43 = 0, $44 = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, $49 = 0, $5 = 0, $50 = 0, $51 = 0, $52 = 0, $53 = 0, $54 = 0, $55 = 0, $56 = 0, $57 = 0, $58 = 0, $59 = 0, $6 = 0;
- var $60 = 0, $61 = 0, $62 = 0, $63 = 0, $64 = 0, $65 = 0, $66 = 0, $67 = 0, $68 = 0, $69 = 0, $7 = 0, $70 = 0, $71 = 0, $72 = 0, $73 = 0, $74 = 0, $75 = 0, $76 = 0, $77 = 0, $78 = 0;
- var $79 = 0, $8 = 0, $80 = 0, $81 = 0, $82 = 0, $83 = 0, $84 = 0, $85 = 0, $86 = 0, $87 = 0, $88 = 0, $89 = 0, $9 = 0, $90 = 0, $91 = 0, $92 = 0, $93 = 0, $94 = 0, $95 = 0, $96 = 0;
- var $97 = 0, $98 = 0, $99 = 0, $F$0$i$i = 0, $F104$0 = 0, $F197$0$i = 0, $F224$0$i$i = 0, $F290$0$i = 0, $I252$0$i$i = 0, $I316$0$i = 0, $I57$0$i$i = 0, $K105$0$i$i = 0, $K305$0$i$i = 0, $K373$0$i = 0, $R$1$i = 0, $R$1$i$168 = 0, $R$1$i$168$lcssa = 0, $R$1$i$i = 0, $R$1$i$i$lcssa = 0, $R$1$i$lcssa = 0;
- var $R$3$i = 0, $R$3$i$171 = 0, $R$3$i$i = 0, $RP$1$i = 0, $RP$1$i$167 = 0, $RP$1$i$167$lcssa = 0, $RP$1$i$i = 0, $RP$1$i$i$lcssa = 0, $RP$1$i$lcssa = 0, $T$0$i = 0, $T$0$i$58$i = 0, $T$0$i$58$i$lcssa = 0, $T$0$i$58$i$lcssa283 = 0, $T$0$i$i = 0, $T$0$i$i$lcssa = 0, $T$0$i$i$lcssa284 = 0, $T$0$i$lcssa = 0, $T$0$i$lcssa293 = 0, $add$i = 0, $add$i$146 = 0;
- var $add$i$180 = 0, $add$i$i = 0, $add$ptr = 0, $add$ptr$i = 0, $add$ptr$i$1$i$i = 0, $add$ptr$i$11$i = 0, $add$ptr$i$161 = 0, $add$ptr$i$193 = 0, $add$ptr$i$21$i = 0, $add$ptr$i$32$i = 0, $add$ptr$i$i = 0, $add$ptr$i$i$i = 0, $add$ptr$i$i$i$lcssa = 0, $add$ptr14$i$i = 0, $add$ptr15$i$i = 0, $add$ptr16$i$i = 0, $add$ptr166 = 0, $add$ptr169 = 0, $add$ptr17$i$i = 0, $add$ptr178 = 0;
- var $add$ptr181$i = 0, $add$ptr182 = 0, $add$ptr189$i = 0, $add$ptr190$i = 0, $add$ptr193 = 0, $add$ptr199 = 0, $add$ptr2$i$i = 0, $add$ptr205$i$i = 0, $add$ptr212$i$i = 0, $add$ptr225$i = 0, $add$ptr227$i = 0, $add$ptr24$i$i = 0, $add$ptr262$i = 0, $add$ptr269$i = 0, $add$ptr273$i = 0, $add$ptr282$i = 0, $add$ptr3$i$i = 0, $add$ptr30$i$i = 0, $add$ptr369$i$i = 0, $add$ptr4$i$26$i = 0;
- var $add$ptr4$i$37$i = 0, $add$ptr4$i$i = 0, $add$ptr4$i$i$i = 0, $add$ptr441$i = 0, $add$ptr5$i$i = 0, $add$ptr6$i$30$i = 0, $add$ptr6$i$i = 0, $add$ptr6$i$i$i = 0, $add$ptr7$i$i = 0, $add$ptr8$i122$i = 0, $add$ptr95 = 0, $add$ptr98 = 0, $add10$i = 0, $add101$i = 0, $add110$i = 0, $add13$i = 0, $add14$i = 0, $add140$i = 0, $add144 = 0, $add150$i = 0;
- var $add17$i = 0, $add17$i$183 = 0, $add177$i = 0, $add18$i = 0, $add19$i = 0, $add2 = 0, $add20$i = 0, $add206$i$i = 0, $add212$i = 0, $add215$i = 0, $add22$i = 0, $add246$i = 0, $add26$i$i = 0, $add268$i = 0, $add269$i$i = 0, $add274$i$i = 0, $add278$i$i = 0, $add280$i$i = 0, $add283$i$i = 0, $add337$i = 0;
- var $add342$i = 0, $add346$i = 0, $add348$i = 0, $add351$i = 0, $add46$i = 0, $add50 = 0, $add51$i = 0, $add54 = 0, $add54$i = 0, $add58 = 0, $add62 = 0, $add64 = 0, $add74$i$i = 0, $add77$i = 0, $add78$i = 0, $add79$i$i = 0, $add8 = 0, $add82$i = 0, $add83$i$i = 0, $add85$i$i = 0;
- var $add86$i = 0, $add88$i$i = 0, $add9$i = 0, $add90$i = 0, $add92$i = 0, $and = 0, $and$i = 0, $and$i$12$i = 0, $and$i$14$i = 0, $and$i$143 = 0, $and$i$22$i = 0, $and$i$33$i = 0, $and$i$i = 0, $and$i$i$i = 0, $and100$i = 0, $and103$i = 0, $and104$i = 0, $and106 = 0, $and11$i = 0, $and119$i$i = 0;
- var $and12$i = 0, $and13$i = 0, $and13$i$i = 0, $and133$i$i = 0, $and14 = 0, $and145 = 0, $and17$i = 0, $and194$i = 0, $and194$i$204 = 0, $and199$i = 0, $and209$i$i = 0, $and21$i = 0, $and21$i$149 = 0, $and227$i$i = 0, $and236$i = 0, $and264$i$i = 0, $and268$i$i = 0, $and273$i$i = 0, $and282$i$i = 0, $and29$i = 0;
- var $and292$i = 0, $and295$i$i = 0, $and3$i = 0, $and3$i$24$i = 0, $and3$i$35$i = 0, $and3$i$i = 0, $and3$i$i$i = 0, $and30$i = 0, $and318$i$i = 0, $and32$i = 0, $and32$i$i = 0, $and33$i$i = 0, $and331$i = 0, $and336$i = 0, $and341$i = 0, $and350$i = 0, $and363$i = 0, $and37$i$i = 0, $and387$i = 0, $and4 = 0;
- var $and40$i$i = 0, $and41 = 0, $and42$i = 0, $and43 = 0, $and46 = 0, $and49 = 0, $and49$i = 0, $and49$i$i = 0, $and53 = 0, $and57 = 0, $and6$i = 0, $and6$i$38$i = 0, $and6$i$i = 0, $and61 = 0, $and64$i = 0, $and68$i = 0, $and69$i$i = 0, $and7 = 0, $and7$i$i = 0, $and73$i = 0;
- var $and73$i$i = 0, $and74 = 0, $and77$i = 0, $and78$i$i = 0, $and8$i = 0, $and80$i = 0, $and81$i = 0, $and85$i = 0, $and87$i$i = 0, $and89$i = 0, $and9$i = 0, $and96$i$i = 0, $arrayidx = 0, $arrayidx$i = 0, $arrayidx$i$150 = 0, $arrayidx$i$20$i = 0, $arrayidx$i$48$i = 0, $arrayidx$i$i = 0, $arrayidx103 = 0, $arrayidx103$i$i = 0;
- var $arrayidx106$i = 0, $arrayidx107$i$i = 0, $arrayidx113$i = 0, $arrayidx113$i$159 = 0, $arrayidx121$i = 0, $arrayidx123$i$i = 0, $arrayidx126$i$i = 0, $arrayidx126$i$i$lcssa = 0, $arrayidx137$i = 0, $arrayidx143$i$i = 0, $arrayidx148$i = 0, $arrayidx151$i = 0, $arrayidx151$i$i = 0, $arrayidx154$i = 0, $arrayidx155$i = 0, $arrayidx161$i = 0, $arrayidx165$i = 0, $arrayidx165$i$169 = 0, $arrayidx178$i$i = 0, $arrayidx184$i = 0;
- var $arrayidx184$i$i = 0, $arrayidx195$i$i = 0, $arrayidx196$i = 0, $arrayidx204$i = 0, $arrayidx212$i = 0, $arrayidx223$i$i = 0, $arrayidx228$i = 0, $arrayidx23$i = 0, $arrayidx239$i = 0, $arrayidx245$i = 0, $arrayidx256$i = 0, $arrayidx27$i = 0, $arrayidx287$i$i = 0, $arrayidx289$i = 0, $arrayidx290$i$i = 0, $arrayidx325$i$i = 0, $arrayidx325$i$i$lcssa = 0, $arrayidx355$i = 0, $arrayidx358$i = 0, $arrayidx394$i = 0;
- var $arrayidx394$i$lcssa = 0, $arrayidx40$i = 0, $arrayidx44$i = 0, $arrayidx61$i = 0, $arrayidx65$i = 0, $arrayidx66 = 0, $arrayidx71$i = 0, $arrayidx75$i = 0, $arrayidx91$i$i = 0, $arrayidx92$i$i = 0, $arrayidx94$i = 0, $arrayidx94$i$156 = 0, $arrayidx96$i$i = 0, $base$i$i$lcssa = 0, $base226$i$lcssa = 0, $bk = 0, $bk$i = 0, $bk$i$163 = 0, $bk$i$46$i = 0, $bk$i$i = 0;
- var $bk102$i$i = 0, $bk122 = 0, $bk124 = 0, $bk136$i = 0, $bk139$i$i = 0, $bk158$i$i = 0, $bk161$i$i = 0, $bk218$i = 0, $bk220$i = 0, $bk246$i$i = 0, $bk248$i$i = 0, $bk302$i$i = 0, $bk311$i = 0, $bk313$i = 0, $bk338$i$i = 0, $bk357$i$i = 0, $bk360$i$i = 0, $bk370$i = 0, $bk407$i = 0, $bk429$i = 0;
- var $bk43$i$i = 0, $bk432$i = 0, $bk47$i = 0, $bk55$i$i = 0, $bk67$i$i = 0, $bk74$i$i = 0, $bk78 = 0, $bk82$i$i = 0, $br$2$ph$i = 0, $call$i$i = 0, $call107$i = 0, $call131$i = 0, $call132$i = 0, $call275$i = 0, $call37$i = 0, $call6$i$i = 0, $call68$i = 0, $call83$i = 0, $child$i$i = 0, $child166$i$i = 0;
- var $child289$i$i = 0, $child357$i = 0, $cmp = 0, $cmp$i = 0, $cmp$i$13$i = 0, $cmp$i$140 = 0, $cmp$i$15$i = 0, $cmp$i$179 = 0, $cmp$i$2$i$i = 0, $cmp$i$23$i = 0, $cmp$i$34$i = 0, $cmp$i$9$i = 0, $cmp$i$i$i = 0, $cmp1 = 0, $cmp1$i = 0, $cmp1$i$i = 0, $cmp10 = 0, $cmp100$i$i = 0, $cmp102$i = 0, $cmp104$i$i = 0;
- var $cmp105$i = 0, $cmp106$i$i = 0, $cmp107$i = 0, $cmp107$i$157 = 0, $cmp108$i = 0, $cmp108$i$i = 0, $cmp112$i$i = 0, $cmp113 = 0, $cmp114$i = 0, $cmp116$i = 0, $cmp118$i = 0, $cmp119$i = 0, $cmp12$i = 0, $cmp120$i$53$i = 0, $cmp120$i$i = 0, $cmp121$i = 0, $cmp123$i = 0, $cmp124$i$i = 0, $cmp126$i = 0, $cmp127$i = 0;
- var $cmp128 = 0, $cmp128$i = 0, $cmp128$i$i = 0, $cmp130$i = 0, $cmp133$i = 0, $cmp133$i$196 = 0, $cmp133$i$i = 0, $cmp135$i = 0, $cmp137$i = 0, $cmp137$i$197 = 0, $cmp137$i$i = 0, $cmp138$i = 0, $cmp139 = 0, $cmp140$i = 0, $cmp141$not$i = 0, $cmp142$i = 0, $cmp144$i$i = 0, $cmp146 = 0, $cmp15 = 0, $cmp15$i = 0;
- var $cmp151$i = 0, $cmp152$i = 0, $cmp153$i$i = 0, $cmp155$i = 0, $cmp156 = 0, $cmp156$i = 0, $cmp156$i$i = 0, $cmp157$i = 0, $cmp159$i = 0, $cmp159$i$199 = 0, $cmp16 = 0, $cmp160$i$i = 0, $cmp162 = 0, $cmp162$i = 0, $cmp162$i$200 = 0, $cmp166$i = 0, $cmp168$i$i = 0, $cmp171$i = 0, $cmp172$i$i = 0, $cmp174$i = 0;
- var $cmp180$i = 0, $cmp185$i = 0, $cmp185$i$i = 0, $cmp186 = 0, $cmp186$i = 0, $cmp189$i$i = 0, $cmp19$i = 0, $cmp190$i = 0, $cmp191$i = 0, $cmp198$i = 0, $cmp2$i$i = 0, $cmp2$i$i$i = 0, $cmp20$i$i = 0, $cmp203$i = 0, $cmp205$i = 0, $cmp208$i = 0, $cmp209$i = 0, $cmp21$i = 0, $cmp215$i$i = 0, $cmp217$i = 0;
- var $cmp218$i = 0, $cmp221$i = 0, $cmp224$i = 0, $cmp228$i = 0, $cmp229$i = 0, $cmp233$i = 0, $cmp236$i$i = 0, $cmp24$i = 0, $cmp24$i$i = 0, $cmp246$i = 0, $cmp250$i = 0, $cmp254$i$i = 0, $cmp257$i = 0, $cmp258$i$i = 0, $cmp26$i = 0, $cmp265$i = 0, $cmp27$i$i = 0, $cmp28$i = 0, $cmp28$i$i = 0, $cmp284$i = 0;
- var $cmp29 = 0, $cmp3$i$i = 0, $cmp301$i = 0, $cmp306$i$i = 0, $cmp31 = 0, $cmp319$i = 0, $cmp319$i$i = 0, $cmp32$i = 0, $cmp32$i$185 = 0, $cmp323$i = 0, $cmp327$i$i = 0, $cmp33$i = 0, $cmp332$i$i = 0, $cmp34$i = 0, $cmp34$i$i = 0, $cmp35$i = 0, $cmp350$i$i = 0, $cmp36$i = 0, $cmp36$i$i = 0, $cmp374$i = 0;
- var $cmp38$i = 0, $cmp38$i$i = 0, $cmp388$i = 0, $cmp396$i = 0, $cmp40$i = 0, $cmp401$i = 0, $cmp41$i$i = 0, $cmp42$i$i = 0, $cmp422$i = 0, $cmp43$i = 0, $cmp44$i$i = 0, $cmp45$i = 0, $cmp45$i$155 = 0, $cmp46$i = 0, $cmp46$i$49$i = 0, $cmp46$i$i = 0, $cmp48$i = 0, $cmp49$i = 0, $cmp5 = 0, $cmp51$i = 0;
- var $cmp54$i$i = 0, $cmp55$i = 0, $cmp55$i$187 = 0, $cmp57$i = 0, $cmp57$i$188 = 0, $cmp57$i$i = 0, $cmp59$i$i = 0, $cmp60$i = 0, $cmp60$i$i = 0, $cmp62$i = 0, $cmp63$i = 0, $cmp63$i$i = 0, $cmp65$i = 0, $cmp66$i = 0, $cmp66$i$190 = 0, $cmp69$i = 0, $cmp7$i$i = 0, $cmp70 = 0, $cmp72$i = 0, $cmp75$i$i = 0;
- var $cmp76 = 0, $cmp76$i = 0, $cmp79 = 0, $cmp81$i = 0, $cmp81$i$191 = 0, $cmp81$i$i = 0, $cmp83$i$i = 0, $cmp85$i = 0, $cmp86$i$i = 0, $cmp89$i = 0, $cmp9$i$i = 0, $cmp90$i = 0, $cmp91$i = 0, $cmp93$i = 0, $cmp95$i = 0, $cmp96$i = 0, $cmp97$7$i = 0, $cmp97$i = 0, $cmp97$i$i = 0, $cmp99 = 0;
- var $cond = 0, $cond$i = 0, $cond$i$16$i = 0, $cond$i$25$i = 0, $cond$i$36$i = 0, $cond$i$i = 0, $cond$i$i$i = 0, $cond$v$0$i = 0, $cond115$i$i = 0, $cond13$i$i = 0, $cond15$i$i = 0, $cond2$i = 0, $cond2$i$i = 0, $cond3$i = 0, $cond315$i$i = 0, $cond383$i = 0, $cond4$i = 0, $exitcond$i$i = 0, $fd$i = 0, $fd$i$164 = 0;
- var $fd$i$i = 0, $fd103$i$i = 0, $fd123 = 0, $fd139$i = 0, $fd140$i$i = 0, $fd148$i$i = 0, $fd160$i$i = 0, $fd219$i = 0, $fd247$i$i = 0, $fd303$i$i = 0, $fd312$i = 0, $fd339$i$i = 0, $fd344$i$i = 0, $fd359$i$i = 0, $fd371$i = 0, $fd408$i = 0, $fd416$i = 0, $fd431$i = 0, $fd50$i = 0, $fd54$i$i = 0;
- var $fd59$i$i = 0, $fd68$pre$phi$i$iZ2D = 0, $fd69 = 0, $fd78$i$i = 0, $fd85$i$i = 0, $fd9 = 0, $head = 0, $head$i = 0, $head$i$154 = 0, $head$i$17$i = 0, $head$i$29$i = 0, $head$i$42$i = 0, $head$i$i = 0, $head$i$i$i = 0, $head118$i$i = 0, $head168 = 0, $head173 = 0, $head177 = 0, $head179 = 0, $head179$i = 0;
- var $head182$i = 0, $head187$i = 0, $head189$i = 0, $head195 = 0, $head198 = 0, $head208$i$i = 0, $head211$i$i = 0, $head23$i$i = 0, $head25 = 0, $head265$i = 0, $head268$i = 0, $head271$i = 0, $head274$i = 0, $head279$i = 0, $head281$i = 0, $head29$i = 0, $head29$i$i = 0, $head317$i$i = 0, $head32$i$i = 0, $head34$i$i = 0;
- var $head386$i = 0, $head7$i$31$i = 0, $head7$i$i = 0, $head7$i$i$i = 0, $head94 = 0, $head97 = 0, $head99$i = 0, $i$01$i$i = 0, $idx$0$i = 0, $inc$i$i = 0, $index$i = 0, $index$i$172 = 0, $index$i$54$i = 0, $index$i$i = 0, $index288$i$i = 0, $index356$i = 0, $nb$0 = 0, $neg = 0, $neg$i = 0, $neg$i$173 = 0;
- var $neg$i$182 = 0, $neg$i$i = 0, $neg103$i = 0, $neg13 = 0, $neg132$i$i = 0, $neg48$i = 0, $neg73 = 0, $next$i = 0, $next$i$i = 0, $next$i$i$i = 0, $next231$i = 0, $not$cmp150$i$i = 0, $not$cmp346$i$i = 0, $not$cmp418$i = 0, $oldfirst$0$i$i = 0, $or$cond$i = 0, $or$cond$i$189 = 0, $or$cond1$i = 0, $or$cond1$i$184 = 0, $or$cond2$i = 0;
- var $or$cond3$i = 0, $or$cond4$i = 0, $or$cond5$i = 0, $or$cond7$i = 0, $or$cond8$i = 0, $or$cond98$i = 0, $or$i = 0, $or$i$195 = 0, $or$i$28$i = 0, $or$i$i = 0, $or$i$i$i = 0, $or101$i$i = 0, $or110 = 0, $or167 = 0, $or172 = 0, $or176 = 0, $or178$i = 0, $or180 = 0, $or183$i = 0, $or186$i = 0;
- var $or188$i = 0, $or19$i$i = 0, $or194 = 0, $or197 = 0, $or204$i = 0, $or210$i$i = 0, $or22$i$i = 0, $or23 = 0, $or232$i$i = 0, $or26 = 0, $or264$i = 0, $or267$i = 0, $or270$i = 0, $or275$i = 0, $or278$i = 0, $or28$i$i = 0, $or280$i = 0, $or297$i = 0, $or300$i$i = 0, $or33$i$i = 0;
- var $or368$i = 0, $or40 = 0, $or44$i$i = 0, $or93 = 0, $or96 = 0, $p$0$i$i = 0, $parent$i = 0, $parent$i$162 = 0, $parent$i$51$i = 0, $parent$i$i = 0, $parent135$i = 0, $parent138$i$i = 0, $parent149$i = 0, $parent162$i$i = 0, $parent165$i$i = 0, $parent166$i = 0, $parent179$i$i = 0, $parent196$i$i = 0, $parent226$i = 0, $parent240$i = 0;
- var $parent257$i = 0, $parent301$i$i = 0, $parent337$i$i = 0, $parent361$i$i = 0, $parent369$i = 0, $parent406$i = 0, $parent433$i = 0, $qsize$0$i$i = 0, $retval$0 = 0, $rsize$0$i = 0, $rsize$0$i$152 = 0, $rsize$0$i$lcssa = 0, $rsize$1$i = 0, $rsize$3$i = 0, $rsize$4$lcssa$i = 0, $rsize$49$i = 0, $rst$0$i = 0, $rst$1$i = 0, $sflags193$i = 0, $sflags235$i = 0;
- var $shl = 0, $shl$i = 0, $shl$i$144 = 0, $shl$i$19$i = 0, $shl$i$47$i = 0, $shl$i$i = 0, $shl102 = 0, $shl105 = 0, $shl116$i$i = 0, $shl12 = 0, $shl127$i$i = 0, $shl131$i$i = 0, $shl15$i = 0, $shl18$i = 0, $shl192$i = 0, $shl195$i = 0, $shl198$i = 0, $shl22 = 0, $shl221$i$i = 0, $shl226$i$i = 0;
- var $shl265$i$i = 0, $shl270$i$i = 0, $shl276$i$i = 0, $shl279$i$i = 0, $shl288$i = 0, $shl291$i = 0, $shl294$i$i = 0, $shl31$i = 0, $shl316$i$i = 0, $shl326$i$i = 0, $shl333$i = 0, $shl338$i = 0, $shl344$i = 0, $shl347$i = 0, $shl35 = 0, $shl362$i = 0, $shl37 = 0, $shl384$i = 0, $shl39$i$i = 0, $shl395$i = 0;
- var $shl48$i$i = 0, $shl52$i = 0, $shl60$i = 0, $shl65 = 0, $shl70$i$i = 0, $shl72 = 0, $shl75$i$i = 0, $shl81$i$i = 0, $shl84$i$i = 0, $shl9$i = 0, $shl90 = 0, $shl95$i$i = 0, $shr = 0, $shr$i = 0, $shr$i$139 = 0, $shr$i$45$i = 0, $shr$i$i = 0, $shr101 = 0, $shr11$i = 0, $shr11$i$147 = 0;
- var $shr110$i$i = 0, $shr12$i = 0, $shr123$i$i = 0, $shr15$i = 0, $shr16$i = 0, $shr16$i$148 = 0, $shr19$i = 0, $shr194$i = 0, $shr20$i = 0, $shr214$i$i = 0, $shr253$i$i = 0, $shr263$i$i = 0, $shr267$i$i = 0, $shr27$i = 0, $shr272$i$i = 0, $shr277$i$i = 0, $shr281$i$i = 0, $shr283$i = 0, $shr3 = 0, $shr310$i$i = 0;
- var $shr318$i = 0, $shr322$i$i = 0, $shr330$i = 0, $shr335$i = 0, $shr340$i = 0, $shr345$i = 0, $shr349$i = 0, $shr378$i = 0, $shr391$i = 0, $shr4$i = 0, $shr41$i = 0, $shr45 = 0, $shr47 = 0, $shr48 = 0, $shr5$i = 0, $shr5$i$142 = 0, $shr51 = 0, $shr52 = 0, $shr55 = 0, $shr56 = 0;
- var $shr58$i$i = 0, $shr59 = 0, $shr60 = 0, $shr63 = 0, $shr68$i$i = 0, $shr7$i = 0, $shr7$i$145 = 0, $shr72$i = 0, $shr72$i$i = 0, $shr75$i = 0, $shr76$i = 0, $shr77$i$i = 0, $shr79$i = 0, $shr8$i = 0, $shr80$i = 0, $shr82$i$i = 0, $shr83$i = 0, $shr84$i = 0, $shr86$i$i = 0, $shr87$i = 0;
- var $shr88$i = 0, $shr91$i = 0, $size$i$i = 0, $size$i$i$i = 0, $size$i$i$lcssa = 0, $size188$i = 0, $size188$i$lcssa = 0, $size245$i = 0, $sizebits$0$i = 0, $sizebits$0$shl52$i = 0, $sp$0$i$i = 0, $sp$0$i$i$i = 0, $sp$0108$i = 0, $sp$0108$i$lcssa = 0, $sp$1107$i = 0, $sp$1107$i$lcssa = 0, $ssize$0$i = 0, $ssize$2$ph$i = 0, $ssize$5$i = 0, $sub = 0;
- var $sub$i = 0, $sub$i$138 = 0, $sub$i$181 = 0, $sub$i$i = 0, $sub$ptr$lhs$cast$i = 0, $sub$ptr$lhs$cast$i$39$i = 0, $sub$ptr$lhs$cast$i$i = 0, $sub$ptr$rhs$cast$i = 0, $sub$ptr$rhs$cast$i$40$i = 0, $sub$ptr$rhs$cast$i$i = 0, $sub$ptr$sub$i = 0, $sub$ptr$sub$i$41$i = 0, $sub$ptr$sub$i$i = 0, $sub10$i = 0, $sub101$i = 0, $sub101$rsize$4$i = 0, $sub112$i = 0, $sub113$i$i = 0, $sub118$i = 0, $sub14$i = 0;
- var $sub16$i$i = 0, $sub160 = 0, $sub172$i = 0, $sub18$i$i = 0, $sub190 = 0, $sub2$i = 0, $sub22$i = 0, $sub260$i = 0, $sub262$i$i = 0, $sub266$i$i = 0, $sub271$i$i = 0, $sub275$i$i = 0, $sub30$i = 0, $sub31$i = 0, $sub31$rsize$0$i = 0, $sub313$i$i = 0, $sub329$i = 0, $sub33$i = 0, $sub334$i = 0, $sub339$i = 0;
- var $sub343$i = 0, $sub381$i = 0, $sub4$i = 0, $sub41$i = 0, $sub42 = 0, $sub44 = 0, $sub5$i$27$i = 0, $sub5$i$i = 0, $sub5$i$i$i = 0, $sub50$i = 0, $sub6$i = 0, $sub63$i = 0, $sub67$i = 0, $sub67$i$i = 0, $sub70$i = 0, $sub71$i$i = 0, $sub76$i$i = 0, $sub80$i$i = 0, $sub91 = 0, $sub99$i = 0;
- var $t$0$i = 0, $t$0$i$151 = 0, $t$2$i = 0, $t$4$ph$i = 0, $t$4$v$4$i = 0, $t$48$i = 0, $tbase$796$i = 0, $tobool$i$i = 0, $tobool107 = 0, $tobool195$i = 0, $tobool200$i = 0, $tobool228$i$i = 0, $tobool237$i = 0, $tobool293$i = 0, $tobool296$i$i = 0, $tobool30$i = 0, $tobool364$i = 0, $tobool97$i$i = 0, $tsize$795$i = 0, $v$0$i = 0;
- var $v$0$i$153 = 0, $v$0$i$lcssa = 0, $v$1$i = 0, $v$3$i = 0, $v$4$lcssa$i = 0, $v$410$i = 0, $xor$i$i = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $cmp = ($bytes>>>0)<(245);
- do {
-  if ($cmp) {
-   $cmp1 = ($bytes>>>0)<(11);
-   $add2 = (($bytes) + 11)|0;
-   $and = $add2 & -8;
-   $cond = $cmp1 ? 16 : $and;
-   $shr = $cond >>> 3;
-   $0 = HEAP32[44]|0;
-   $shr3 = $0 >>> $shr;
-   $and4 = $shr3 & 3;
-   $cmp5 = ($and4|0)==(0);
-   if (!($cmp5)) {
-    $neg = $shr3 & 1;
-    $and7 = $neg ^ 1;
-    $add8 = (($and7) + ($shr))|0;
-    $shl = $add8 << 1;
-    $arrayidx = (216 + ($shl<<2)|0);
-    $1 = ((($arrayidx)) + 8|0);
-    $2 = HEAP32[$1>>2]|0;
-    $fd9 = ((($2)) + 8|0);
-    $3 = HEAP32[$fd9>>2]|0;
-    $cmp10 = ($arrayidx|0)==($3|0);
-    do {
-     if ($cmp10) {
-      $shl12 = 1 << $add8;
-      $neg13 = $shl12 ^ -1;
-      $and14 = $0 & $neg13;
-      HEAP32[44] = $and14;
-     } else {
-      $4 = HEAP32[(192)>>2]|0;
-      $cmp15 = ($3>>>0)<($4>>>0);
-      if ($cmp15) {
-       _abort();
-       // unreachable;
-      }
-      $bk = ((($3)) + 12|0);
-      $5 = HEAP32[$bk>>2]|0;
-      $cmp16 = ($5|0)==($2|0);
-      if ($cmp16) {
-       HEAP32[$bk>>2] = $arrayidx;
-       HEAP32[$1>>2] = $3;
-       break;
-      } else {
-       _abort();
-       // unreachable;
-      }
-     }
-    } while(0);
-    $shl22 = $add8 << 3;
-    $or23 = $shl22 | 3;
-    $head = ((($2)) + 4|0);
-    HEAP32[$head>>2] = $or23;
-    $add$ptr = (($2) + ($shl22)|0);
-    $head25 = ((($add$ptr)) + 4|0);
-    $6 = HEAP32[$head25>>2]|0;
-    $or26 = $6 | 1;
-    HEAP32[$head25>>2] = $or26;
-    $retval$0 = $fd9;
-    return ($retval$0|0);
-   }
-   $7 = HEAP32[(184)>>2]|0;
-   $cmp29 = ($cond>>>0)>($7>>>0);
-   if ($cmp29) {
-    $cmp31 = ($shr3|0)==(0);
-    if (!($cmp31)) {
-     $shl35 = $shr3 << $shr;
-     $shl37 = 2 << $shr;
-     $sub = (0 - ($shl37))|0;
-     $or40 = $shl37 | $sub;
-     $and41 = $shl35 & $or40;
-     $sub42 = (0 - ($and41))|0;
-     $and43 = $and41 & $sub42;
-     $sub44 = (($and43) + -1)|0;
-     $shr45 = $sub44 >>> 12;
-     $and46 = $shr45 & 16;
-     $shr47 = $sub44 >>> $and46;
-     $shr48 = $shr47 >>> 5;
-     $and49 = $shr48 & 8;
-     $add50 = $and49 | $and46;
-     $shr51 = $shr47 >>> $and49;
-     $shr52 = $shr51 >>> 2;
-     $and53 = $shr52 & 4;
-     $add54 = $add50 | $and53;
-     $shr55 = $shr51 >>> $and53;
-     $shr56 = $shr55 >>> 1;
-     $and57 = $shr56 & 2;
-     $add58 = $add54 | $and57;
-     $shr59 = $shr55 >>> $and57;
-     $shr60 = $shr59 >>> 1;
-     $and61 = $shr60 & 1;
-     $add62 = $add58 | $and61;
-     $shr63 = $shr59 >>> $and61;
-     $add64 = (($add62) + ($shr63))|0;
-     $shl65 = $add64 << 1;
-     $arrayidx66 = (216 + ($shl65<<2)|0);
-     $8 = ((($arrayidx66)) + 8|0);
-     $9 = HEAP32[$8>>2]|0;
-     $fd69 = ((($9)) + 8|0);
-     $10 = HEAP32[$fd69>>2]|0;
-     $cmp70 = ($arrayidx66|0)==($10|0);
-     do {
-      if ($cmp70) {
-       $shl72 = 1 << $add64;
-       $neg73 = $shl72 ^ -1;
-       $and74 = $0 & $neg73;
-       HEAP32[44] = $and74;
-       $13 = $7;
-      } else {
-       $11 = HEAP32[(192)>>2]|0;
-       $cmp76 = ($10>>>0)<($11>>>0);
-       if ($cmp76) {
-        _abort();
-        // unreachable;
-       }
-       $bk78 = ((($10)) + 12|0);
-       $12 = HEAP32[$bk78>>2]|0;
-       $cmp79 = ($12|0)==($9|0);
-       if ($cmp79) {
-        HEAP32[$bk78>>2] = $arrayidx66;
-        HEAP32[$8>>2] = $10;
-        $$pre = HEAP32[(184)>>2]|0;
-        $13 = $$pre;
-        break;
-       } else {
-        _abort();
-        // unreachable;
-       }
-      }
-     } while(0);
-     $shl90 = $add64 << 3;
-     $sub91 = (($shl90) - ($cond))|0;
-     $or93 = $cond | 3;
-     $head94 = ((($9)) + 4|0);
-     HEAP32[$head94>>2] = $or93;
-     $add$ptr95 = (($9) + ($cond)|0);
-     $or96 = $sub91 | 1;
-     $head97 = ((($add$ptr95)) + 4|0);
-     HEAP32[$head97>>2] = $or96;
-     $add$ptr98 = (($add$ptr95) + ($sub91)|0);
-     HEAP32[$add$ptr98>>2] = $sub91;
-     $cmp99 = ($13|0)==(0);
-     if (!($cmp99)) {
-      $14 = HEAP32[(196)>>2]|0;
-      $shr101 = $13 >>> 3;
-      $shl102 = $shr101 << 1;
-      $arrayidx103 = (216 + ($shl102<<2)|0);
-      $15 = HEAP32[44]|0;
-      $shl105 = 1 << $shr101;
-      $and106 = $15 & $shl105;
-      $tobool107 = ($and106|0)==(0);
-      if ($tobool107) {
-       $or110 = $15 | $shl105;
-       HEAP32[44] = $or110;
-       $$pre241 = ((($arrayidx103)) + 8|0);
-       $$pre$phiZ2D = $$pre241;$F104$0 = $arrayidx103;
-      } else {
-       $16 = ((($arrayidx103)) + 8|0);
-       $17 = HEAP32[$16>>2]|0;
-       $18 = HEAP32[(192)>>2]|0;
-       $cmp113 = ($17>>>0)<($18>>>0);
-       if ($cmp113) {
-        _abort();
-        // unreachable;
-       } else {
-        $$pre$phiZ2D = $16;$F104$0 = $17;
-       }
-      }
-      HEAP32[$$pre$phiZ2D>>2] = $14;
-      $bk122 = ((($F104$0)) + 12|0);
-      HEAP32[$bk122>>2] = $14;
-      $fd123 = ((($14)) + 8|0);
-      HEAP32[$fd123>>2] = $F104$0;
-      $bk124 = ((($14)) + 12|0);
-      HEAP32[$bk124>>2] = $arrayidx103;
-     }
-     HEAP32[(184)>>2] = $sub91;
-     HEAP32[(196)>>2] = $add$ptr95;
-     $retval$0 = $fd69;
-     return ($retval$0|0);
-    }
-    $19 = HEAP32[(180)>>2]|0;
-    $cmp128 = ($19|0)==(0);
-    if ($cmp128) {
-     $nb$0 = $cond;
-    } else {
-     $sub$i = (0 - ($19))|0;
-     $and$i = $19 & $sub$i;
-     $sub2$i = (($and$i) + -1)|0;
-     $shr$i = $sub2$i >>> 12;
-     $and3$i = $shr$i & 16;
-     $shr4$i = $sub2$i >>> $and3$i;
-     $shr5$i = $shr4$i >>> 5;
-     $and6$i = $shr5$i & 8;
-     $add$i = $and6$i | $and3$i;
-     $shr7$i = $shr4$i >>> $and6$i;
-     $shr8$i = $shr7$i >>> 2;
-     $and9$i = $shr8$i & 4;
-     $add10$i = $add$i | $and9$i;
-     $shr11$i = $shr7$i >>> $and9$i;
-     $shr12$i = $shr11$i >>> 1;
-     $and13$i = $shr12$i & 2;
-     $add14$i = $add10$i | $and13$i;
-     $shr15$i = $shr11$i >>> $and13$i;
-     $shr16$i = $shr15$i >>> 1;
-     $and17$i = $shr16$i & 1;
-     $add18$i = $add14$i | $and17$i;
-     $shr19$i = $shr15$i >>> $and17$i;
-     $add20$i = (($add18$i) + ($shr19$i))|0;
-     $arrayidx$i = (480 + ($add20$i<<2)|0);
-     $20 = HEAP32[$arrayidx$i>>2]|0;
-     $head$i = ((($20)) + 4|0);
-     $21 = HEAP32[$head$i>>2]|0;
-     $and21$i = $21 & -8;
-     $sub22$i = (($and21$i) - ($cond))|0;
-     $rsize$0$i = $sub22$i;$t$0$i = $20;$v$0$i = $20;
-     while(1) {
-      $arrayidx23$i = ((($t$0$i)) + 16|0);
-      $22 = HEAP32[$arrayidx23$i>>2]|0;
-      $cmp$i = ($22|0)==(0|0);
-      if ($cmp$i) {
-       $arrayidx27$i = ((($t$0$i)) + 20|0);
-       $23 = HEAP32[$arrayidx27$i>>2]|0;
-       $cmp28$i = ($23|0)==(0|0);
-       if ($cmp28$i) {
-        $rsize$0$i$lcssa = $rsize$0$i;$v$0$i$lcssa = $v$0$i;
-        break;
-       } else {
-        $cond4$i = $23;
-       }
-      } else {
-       $cond4$i = $22;
-      }
-      $head29$i = ((($cond4$i)) + 4|0);
-      $24 = HEAP32[$head29$i>>2]|0;
-      $and30$i = $24 & -8;
-      $sub31$i = (($and30$i) - ($cond))|0;
-      $cmp32$i = ($sub31$i>>>0)<($rsize$0$i>>>0);
-      $sub31$rsize$0$i = $cmp32$i ? $sub31$i : $rsize$0$i;
-      $cond$v$0$i = $cmp32$i ? $cond4$i : $v$0$i;
-      $rsize$0$i = $sub31$rsize$0$i;$t$0$i = $cond4$i;$v$0$i = $cond$v$0$i;
-     }
-     $25 = HEAP32[(192)>>2]|0;
-     $cmp33$i = ($v$0$i$lcssa>>>0)<($25>>>0);
-     if ($cmp33$i) {
-      _abort();
-      // unreachable;
-     }
-     $add$ptr$i = (($v$0$i$lcssa) + ($cond)|0);
-     $cmp35$i = ($v$0$i$lcssa>>>0)<($add$ptr$i>>>0);
-     if (!($cmp35$i)) {
-      _abort();
-      // unreachable;
-     }
-     $parent$i = ((($v$0$i$lcssa)) + 24|0);
-     $26 = HEAP32[$parent$i>>2]|0;
-     $bk$i = ((($v$0$i$lcssa)) + 12|0);
-     $27 = HEAP32[$bk$i>>2]|0;
-     $cmp40$i = ($27|0)==($v$0$i$lcssa|0);
-     do {
-      if ($cmp40$i) {
-       $arrayidx61$i = ((($v$0$i$lcssa)) + 20|0);
-       $31 = HEAP32[$arrayidx61$i>>2]|0;
-       $cmp62$i = ($31|0)==(0|0);
-       if ($cmp62$i) {
-        $arrayidx65$i = ((($v$0$i$lcssa)) + 16|0);
-        $32 = HEAP32[$arrayidx65$i>>2]|0;
-        $cmp66$i = ($32|0)==(0|0);
-        if ($cmp66$i) {
-         $R$3$i = 0;
-         break;
-        } else {
-         $R$1$i = $32;$RP$1$i = $arrayidx65$i;
-        }
-       } else {
-        $R$1$i = $31;$RP$1$i = $arrayidx61$i;
-       }
-       while(1) {
-        $arrayidx71$i = ((($R$1$i)) + 20|0);
-        $33 = HEAP32[$arrayidx71$i>>2]|0;
-        $cmp72$i = ($33|0)==(0|0);
-        if (!($cmp72$i)) {
-         $R$1$i = $33;$RP$1$i = $arrayidx71$i;
-         continue;
-        }
-        $arrayidx75$i = ((($R$1$i)) + 16|0);
-        $34 = HEAP32[$arrayidx75$i>>2]|0;
-        $cmp76$i = ($34|0)==(0|0);
-        if ($cmp76$i) {
-         $R$1$i$lcssa = $R$1$i;$RP$1$i$lcssa = $RP$1$i;
-         break;
-        } else {
-         $R$1$i = $34;$RP$1$i = $arrayidx75$i;
-        }
-       }
-       $cmp81$i = ($RP$1$i$lcssa>>>0)<($25>>>0);
-       if ($cmp81$i) {
-        _abort();
-        // unreachable;
-       } else {
-        HEAP32[$RP$1$i$lcssa>>2] = 0;
-        $R$3$i = $R$1$i$lcssa;
-        break;
-       }
-      } else {
-       $fd$i = ((($v$0$i$lcssa)) + 8|0);
-       $28 = HEAP32[$fd$i>>2]|0;
-       $cmp45$i = ($28>>>0)<($25>>>0);
-       if ($cmp45$i) {
-        _abort();
-        // unreachable;
-       }
-       $bk47$i = ((($28)) + 12|0);
-       $29 = HEAP32[$bk47$i>>2]|0;
-       $cmp48$i = ($29|0)==($v$0$i$lcssa|0);
-       if (!($cmp48$i)) {
-        _abort();
-        // unreachable;
-       }
-       $fd50$i = ((($27)) + 8|0);
-       $30 = HEAP32[$fd50$i>>2]|0;
-       $cmp51$i = ($30|0)==($v$0$i$lcssa|0);
-       if ($cmp51$i) {
-        HEAP32[$bk47$i>>2] = $27;
-        HEAP32[$fd50$i>>2] = $28;
-        $R$3$i = $27;
-        break;
-       } else {
-        _abort();
-        // unreachable;
-       }
-      }
-     } while(0);
-     $cmp90$i = ($26|0)==(0|0);
-     do {
-      if (!($cmp90$i)) {
-       $index$i = ((($v$0$i$lcssa)) + 28|0);
-       $35 = HEAP32[$index$i>>2]|0;
-       $arrayidx94$i = (480 + ($35<<2)|0);
-       $36 = HEAP32[$arrayidx94$i>>2]|0;
-       $cmp95$i = ($v$0$i$lcssa|0)==($36|0);
-       if ($cmp95$i) {
-        HEAP32[$arrayidx94$i>>2] = $R$3$i;
-        $cond2$i = ($R$3$i|0)==(0|0);
-        if ($cond2$i) {
-         $shl$i = 1 << $35;
-         $neg$i = $shl$i ^ -1;
-         $37 = HEAP32[(180)>>2]|0;
-         $and103$i = $37 & $neg$i;
-         HEAP32[(180)>>2] = $and103$i;
-         break;
-        }
-       } else {
-        $38 = HEAP32[(192)>>2]|0;
-        $cmp107$i = ($26>>>0)<($38>>>0);
-        if ($cmp107$i) {
-         _abort();
-         // unreachable;
-        }
-        $arrayidx113$i = ((($26)) + 16|0);
-        $39 = HEAP32[$arrayidx113$i>>2]|0;
-        $cmp114$i = ($39|0)==($v$0$i$lcssa|0);
-        if ($cmp114$i) {
-         HEAP32[$arrayidx113$i>>2] = $R$3$i;
-        } else {
-         $arrayidx121$i = ((($26)) + 20|0);
-         HEAP32[$arrayidx121$i>>2] = $R$3$i;
-        }
-        $cmp126$i = ($R$3$i|0)==(0|0);
-        if ($cmp126$i) {
-         break;
-        }
-       }
-       $40 = HEAP32[(192)>>2]|0;
-       $cmp130$i = ($R$3$i>>>0)<($40>>>0);
-       if ($cmp130$i) {
-        _abort();
-        // unreachable;
-       }
-       $parent135$i = ((($R$3$i)) + 24|0);
-       HEAP32[$parent135$i>>2] = $26;
-       $arrayidx137$i = ((($v$0$i$lcssa)) + 16|0);
-       $41 = HEAP32[$arrayidx137$i>>2]|0;
-       $cmp138$i = ($41|0)==(0|0);
-       do {
-        if (!($cmp138$i)) {
-         $cmp142$i = ($41>>>0)<($40>>>0);
-         if ($cmp142$i) {
-          _abort();
-          // unreachable;
-         } else {
-          $arrayidx148$i = ((($R$3$i)) + 16|0);
-          HEAP32[$arrayidx148$i>>2] = $41;
-          $parent149$i = ((($41)) + 24|0);
-          HEAP32[$parent149$i>>2] = $R$3$i;
-          break;
-         }
-        }
-       } while(0);
-       $arrayidx154$i = ((($v$0$i$lcssa)) + 20|0);
-       $42 = HEAP32[$arrayidx154$i>>2]|0;
-       $cmp155$i = ($42|0)==(0|0);
-       if (!($cmp155$i)) {
-        $43 = HEAP32[(192)>>2]|0;
-        $cmp159$i = ($42>>>0)<($43>>>0);
-        if ($cmp159$i) {
-         _abort();
-         // unreachable;
-        } else {
-         $arrayidx165$i = ((($R$3$i)) + 20|0);
-         HEAP32[$arrayidx165$i>>2] = $42;
-         $parent166$i = ((($42)) + 24|0);
-         HEAP32[$parent166$i>>2] = $R$3$i;
-         break;
-        }
-       }
-      }
-     } while(0);
-     $cmp174$i = ($rsize$0$i$lcssa>>>0)<(16);
-     if ($cmp174$i) {
-      $add177$i = (($rsize$0$i$lcssa) + ($cond))|0;
-      $or178$i = $add177$i | 3;
-      $head179$i = ((($v$0$i$lcssa)) + 4|0);
-      HEAP32[$head179$i>>2] = $or178$i;
-      $add$ptr181$i = (($v$0$i$lcssa) + ($add177$i)|0);
-      $head182$i = ((($add$ptr181$i)) + 4|0);
-      $44 = HEAP32[$head182$i>>2]|0;
-      $or183$i = $44 | 1;
-      HEAP32[$head182$i>>2] = $or183$i;
-     } else {
-      $or186$i = $cond | 3;
-      $head187$i = ((($v$0$i$lcssa)) + 4|0);
-      HEAP32[$head187$i>>2] = $or186$i;
-      $or188$i = $rsize$0$i$lcssa | 1;
-      $head189$i = ((($add$ptr$i)) + 4|0);
-      HEAP32[$head189$i>>2] = $or188$i;
-      $add$ptr190$i = (($add$ptr$i) + ($rsize$0$i$lcssa)|0);
-      HEAP32[$add$ptr190$i>>2] = $rsize$0$i$lcssa;
-      $45 = HEAP32[(184)>>2]|0;
-      $cmp191$i = ($45|0)==(0);
-      if (!($cmp191$i)) {
-       $46 = HEAP32[(196)>>2]|0;
-       $shr194$i = $45 >>> 3;
-       $shl195$i = $shr194$i << 1;
-       $arrayidx196$i = (216 + ($shl195$i<<2)|0);
-       $47 = HEAP32[44]|0;
-       $shl198$i = 1 << $shr194$i;
-       $and199$i = $47 & $shl198$i;
-       $tobool200$i = ($and199$i|0)==(0);
-       if ($tobool200$i) {
-        $or204$i = $47 | $shl198$i;
-        HEAP32[44] = $or204$i;
-        $$pre$i = ((($arrayidx196$i)) + 8|0);
-        $$pre$phi$iZ2D = $$pre$i;$F197$0$i = $arrayidx196$i;
-       } else {
-        $48 = ((($arrayidx196$i)) + 8|0);
-        $49 = HEAP32[$48>>2]|0;
-        $50 = HEAP32[(192)>>2]|0;
-        $cmp208$i = ($49>>>0)<($50>>>0);
-        if ($cmp208$i) {
-         _abort();
-         // unreachable;
-        } else {
-         $$pre$phi$iZ2D = $48;$F197$0$i = $49;
-        }
-       }
-       HEAP32[$$pre$phi$iZ2D>>2] = $46;
-       $bk218$i = ((($F197$0$i)) + 12|0);
-       HEAP32[$bk218$i>>2] = $46;
-       $fd219$i = ((($46)) + 8|0);
-       HEAP32[$fd219$i>>2] = $F197$0$i;
-       $bk220$i = ((($46)) + 12|0);
-       HEAP32[$bk220$i>>2] = $arrayidx196$i;
-      }
-      HEAP32[(184)>>2] = $rsize$0$i$lcssa;
-      HEAP32[(196)>>2] = $add$ptr$i;
-     }
-     $add$ptr225$i = ((($v$0$i$lcssa)) + 8|0);
-     $retval$0 = $add$ptr225$i;
-     return ($retval$0|0);
-    }
-   } else {
-    $nb$0 = $cond;
-   }
-  } else {
-   $cmp139 = ($bytes>>>0)>(4294967231);
-   if ($cmp139) {
-    $nb$0 = -1;
-   } else {
-    $add144 = (($bytes) + 11)|0;
-    $and145 = $add144 & -8;
-    $51 = HEAP32[(180)>>2]|0;
-    $cmp146 = ($51|0)==(0);
-    if ($cmp146) {
-     $nb$0 = $and145;
-    } else {
-     $sub$i$138 = (0 - ($and145))|0;
-     $shr$i$139 = $add144 >>> 8;
-     $cmp$i$140 = ($shr$i$139|0)==(0);
-     if ($cmp$i$140) {
-      $idx$0$i = 0;
-     } else {
-      $cmp1$i = ($and145>>>0)>(16777215);
-      if ($cmp1$i) {
-       $idx$0$i = 31;
-      } else {
-       $sub4$i = (($shr$i$139) + 1048320)|0;
-       $shr5$i$142 = $sub4$i >>> 16;
-       $and$i$143 = $shr5$i$142 & 8;
-       $shl$i$144 = $shr$i$139 << $and$i$143;
-       $sub6$i = (($shl$i$144) + 520192)|0;
-       $shr7$i$145 = $sub6$i >>> 16;
-       $and8$i = $shr7$i$145 & 4;
-       $add$i$146 = $and8$i | $and$i$143;
-       $shl9$i = $shl$i$144 << $and8$i;
-       $sub10$i = (($shl9$i) + 245760)|0;
-       $shr11$i$147 = $sub10$i >>> 16;
-       $and12$i = $shr11$i$147 & 2;
-       $add13$i = $add$i$146 | $and12$i;
-       $sub14$i = (14 - ($add13$i))|0;
-       $shl15$i = $shl9$i << $and12$i;
-       $shr16$i$148 = $shl15$i >>> 15;
-       $add17$i = (($sub14$i) + ($shr16$i$148))|0;
-       $shl18$i = $add17$i << 1;
-       $add19$i = (($add17$i) + 7)|0;
-       $shr20$i = $and145 >>> $add19$i;
-       $and21$i$149 = $shr20$i & 1;
-       $add22$i = $and21$i$149 | $shl18$i;
-       $idx$0$i = $add22$i;
-      }
-     }
-     $arrayidx$i$150 = (480 + ($idx$0$i<<2)|0);
-     $52 = HEAP32[$arrayidx$i$150>>2]|0;
-     $cmp24$i = ($52|0)==(0|0);
-     L123: do {
-      if ($cmp24$i) {
-       $rsize$3$i = $sub$i$138;$t$2$i = 0;$v$3$i = 0;
-       label = 86;
-      } else {
-       $cmp26$i = ($idx$0$i|0)==(31);
-       $shr27$i = $idx$0$i >>> 1;
-       $sub30$i = (25 - ($shr27$i))|0;
-       $cond$i = $cmp26$i ? 0 : $sub30$i;
-       $shl31$i = $and145 << $cond$i;
-       $rsize$0$i$152 = $sub$i$138;$rst$0$i = 0;$sizebits$0$i = $shl31$i;$t$0$i$151 = $52;$v$0$i$153 = 0;
-       while(1) {
-        $head$i$154 = ((($t$0$i$151)) + 4|0);
-        $53 = HEAP32[$head$i$154>>2]|0;
-        $and32$i = $53 & -8;
-        $sub33$i = (($and32$i) - ($and145))|0;
-        $cmp34$i = ($sub33$i>>>0)<($rsize$0$i$152>>>0);
-        if ($cmp34$i) {
-         $cmp36$i = ($and32$i|0)==($and145|0);
-         if ($cmp36$i) {
-          $rsize$49$i = $sub33$i;$t$48$i = $t$0$i$151;$v$410$i = $t$0$i$151;
-          label = 90;
-          break L123;
-         } else {
-          $rsize$1$i = $sub33$i;$v$1$i = $t$0$i$151;
-         }
-        } else {
-         $rsize$1$i = $rsize$0$i$152;$v$1$i = $v$0$i$153;
-        }
-        $arrayidx40$i = ((($t$0$i$151)) + 20|0);
-        $54 = HEAP32[$arrayidx40$i>>2]|0;
-        $shr41$i = $sizebits$0$i >>> 31;
-        $arrayidx44$i = (((($t$0$i$151)) + 16|0) + ($shr41$i<<2)|0);
-        $55 = HEAP32[$arrayidx44$i>>2]|0;
-        $cmp45$i$155 = ($54|0)==(0|0);
-        $cmp46$i = ($54|0)==($55|0);
-        $or$cond1$i = $cmp45$i$155 | $cmp46$i;
-        $rst$1$i = $or$cond1$i ? $rst$0$i : $54;
-        $cmp49$i = ($55|0)==(0|0);
-        $56 = $cmp49$i&1;
-        $shl52$i = $56 ^ 1;
-        $sizebits$0$shl52$i = $sizebits$0$i << $shl52$i;
-        if ($cmp49$i) {
-         $rsize$3$i = $rsize$1$i;$t$2$i = $rst$1$i;$v$3$i = $v$1$i;
-         label = 86;
-         break;
-        } else {
-         $rsize$0$i$152 = $rsize$1$i;$rst$0$i = $rst$1$i;$sizebits$0$i = $sizebits$0$shl52$i;$t$0$i$151 = $55;$v$0$i$153 = $v$1$i;
-        }
-       }
-      }
-     } while(0);
-     if ((label|0) == 86) {
-      $cmp55$i = ($t$2$i|0)==(0|0);
-      $cmp57$i = ($v$3$i|0)==(0|0);
-      $or$cond$i = $cmp55$i & $cmp57$i;
-      if ($or$cond$i) {
-       $shl60$i = 2 << $idx$0$i;
-       $sub63$i = (0 - ($shl60$i))|0;
-       $or$i = $shl60$i | $sub63$i;
-       $and64$i = $51 & $or$i;
-       $cmp65$i = ($and64$i|0)==(0);
-       if ($cmp65$i) {
-        $nb$0 = $and145;
-        break;
-       }
-       $sub67$i = (0 - ($and64$i))|0;
-       $and68$i = $and64$i & $sub67$i;
-       $sub70$i = (($and68$i) + -1)|0;
-       $shr72$i = $sub70$i >>> 12;
-       $and73$i = $shr72$i & 16;
-       $shr75$i = $sub70$i >>> $and73$i;
-       $shr76$i = $shr75$i >>> 5;
-       $and77$i = $shr76$i & 8;
-       $add78$i = $and77$i | $and73$i;
-       $shr79$i = $shr75$i >>> $and77$i;
-       $shr80$i = $shr79$i >>> 2;
-       $and81$i = $shr80$i & 4;
-       $add82$i = $add78$i | $and81$i;
-       $shr83$i = $shr79$i >>> $and81$i;
-       $shr84$i = $shr83$i >>> 1;
-       $and85$i = $shr84$i & 2;
-       $add86$i = $add82$i | $and85$i;
-       $shr87$i = $shr83$i >>> $and85$i;
-       $shr88$i = $shr87$i >>> 1;
-       $and89$i = $shr88$i & 1;
-       $add90$i = $add86$i | $and89$i;
-       $shr91$i = $shr87$i >>> $and89$i;
-       $add92$i = (($add90$i) + ($shr91$i))|0;
-       $arrayidx94$i$156 = (480 + ($add92$i<<2)|0);
-       $57 = HEAP32[$arrayidx94$i$156>>2]|0;
-       $t$4$ph$i = $57;
-      } else {
-       $t$4$ph$i = $t$2$i;
-      }
-      $cmp97$7$i = ($t$4$ph$i|0)==(0|0);
-      if ($cmp97$7$i) {
-       $rsize$4$lcssa$i = $rsize$3$i;$v$4$lcssa$i = $v$3$i;
-      } else {
-       $rsize$49$i = $rsize$3$i;$t$48$i = $t$4$ph$i;$v$410$i = $v$3$i;
-       label = 90;
-      }
-     }
-     if ((label|0) == 90) {
-      while(1) {
-       label = 0;
-       $head99$i = ((($t$48$i)) + 4|0);
-       $58 = HEAP32[$head99$i>>2]|0;
-       $and100$i = $58 & -8;
-       $sub101$i = (($and100$i) - ($and145))|0;
-       $cmp102$i = ($sub101$i>>>0)<($rsize$49$i>>>0);
-       $sub101$rsize$4$i = $cmp102$i ? $sub101$i : $rsize$49$i;
-       $t$4$v$4$i = $cmp102$i ? $t$48$i : $v$410$i;
-       $arrayidx106$i = ((($t$48$i)) + 16|0);
-       $59 = HEAP32[$arrayidx106$i>>2]|0;
-       $cmp107$i$157 = ($59|0)==(0|0);
-       if (!($cmp107$i$157)) {
-        $rsize$49$i = $sub101$rsize$4$i;$t$48$i = $59;$v$410$i = $t$4$v$4$i;
-        label = 90;
-        continue;
-       }
-       $arrayidx113$i$159 = ((($t$48$i)) + 20|0);
-       $60 = HEAP32[$arrayidx113$i$159>>2]|0;
-       $cmp97$i = ($60|0)==(0|0);
-       if ($cmp97$i) {
-        $rsize$4$lcssa$i = $sub101$rsize$4$i;$v$4$lcssa$i = $t$4$v$4$i;
-        break;
-       } else {
-        $rsize$49$i = $sub101$rsize$4$i;$t$48$i = $60;$v$410$i = $t$4$v$4$i;
-        label = 90;
-       }
-      }
-     }
-     $cmp116$i = ($v$4$lcssa$i|0)==(0|0);
-     if ($cmp116$i) {
-      $nb$0 = $and145;
-     } else {
-      $61 = HEAP32[(184)>>2]|0;
-      $sub118$i = (($61) - ($and145))|0;
-      $cmp119$i = ($rsize$4$lcssa$i>>>0)<($sub118$i>>>0);
-      if ($cmp119$i) {
-       $62 = HEAP32[(192)>>2]|0;
-       $cmp121$i = ($v$4$lcssa$i>>>0)<($62>>>0);
-       if ($cmp121$i) {
-        _abort();
-        // unreachable;
-       }
-       $add$ptr$i$161 = (($v$4$lcssa$i) + ($and145)|0);
-       $cmp123$i = ($v$4$lcssa$i>>>0)<($add$ptr$i$161>>>0);
-       if (!($cmp123$i)) {
-        _abort();
-        // unreachable;
-       }
-       $parent$i$162 = ((($v$4$lcssa$i)) + 24|0);
-       $63 = HEAP32[$parent$i$162>>2]|0;
-       $bk$i$163 = ((($v$4$lcssa$i)) + 12|0);
-       $64 = HEAP32[$bk$i$163>>2]|0;
-       $cmp128$i = ($64|0)==($v$4$lcssa$i|0);
-       do {
-        if ($cmp128$i) {
-         $arrayidx151$i = ((($v$4$lcssa$i)) + 20|0);
-         $68 = HEAP32[$arrayidx151$i>>2]|0;
-         $cmp152$i = ($68|0)==(0|0);
-         if ($cmp152$i) {
-          $arrayidx155$i = ((($v$4$lcssa$i)) + 16|0);
-          $69 = HEAP32[$arrayidx155$i>>2]|0;
-          $cmp156$i = ($69|0)==(0|0);
-          if ($cmp156$i) {
-           $R$3$i$171 = 0;
-           break;
-          } else {
-           $R$1$i$168 = $69;$RP$1$i$167 = $arrayidx155$i;
-          }
-         } else {
-          $R$1$i$168 = $68;$RP$1$i$167 = $arrayidx151$i;
-         }
-         while(1) {
-          $arrayidx161$i = ((($R$1$i$168)) + 20|0);
-          $70 = HEAP32[$arrayidx161$i>>2]|0;
-          $cmp162$i = ($70|0)==(0|0);
-          if (!($cmp162$i)) {
-           $R$1$i$168 = $70;$RP$1$i$167 = $arrayidx161$i;
-           continue;
-          }
-          $arrayidx165$i$169 = ((($R$1$i$168)) + 16|0);
-          $71 = HEAP32[$arrayidx165$i$169>>2]|0;
-          $cmp166$i = ($71|0)==(0|0);
-          if ($cmp166$i) {
-           $R$1$i$168$lcssa = $R$1$i$168;$RP$1$i$167$lcssa = $RP$1$i$167;
-           break;
-          } else {
-           $R$1$i$168 = $71;$RP$1$i$167 = $arrayidx165$i$169;
-          }
-         }
-         $cmp171$i = ($RP$1$i$167$lcssa>>>0)<($62>>>0);
-         if ($cmp171$i) {
-          _abort();
-          // unreachable;
-         } else {
-          HEAP32[$RP$1$i$167$lcssa>>2] = 0;
-          $R$3$i$171 = $R$1$i$168$lcssa;
-          break;
-         }
-        } else {
-         $fd$i$164 = ((($v$4$lcssa$i)) + 8|0);
-         $65 = HEAP32[$fd$i$164>>2]|0;
-         $cmp133$i = ($65>>>0)<($62>>>0);
-         if ($cmp133$i) {
-          _abort();
-          // unreachable;
-         }
-         $bk136$i = ((($65)) + 12|0);
-         $66 = HEAP32[$bk136$i>>2]|0;
-         $cmp137$i = ($66|0)==($v$4$lcssa$i|0);
-         if (!($cmp137$i)) {
-          _abort();
-          // unreachable;
-         }
-         $fd139$i = ((($64)) + 8|0);
-         $67 = HEAP32[$fd139$i>>2]|0;
-         $cmp140$i = ($67|0)==($v$4$lcssa$i|0);
-         if ($cmp140$i) {
-          HEAP32[$bk136$i>>2] = $64;
-          HEAP32[$fd139$i>>2] = $65;
-          $R$3$i$171 = $64;
-          break;
-         } else {
-          _abort();
-          // unreachable;
-         }
-        }
-       } while(0);
-       $cmp180$i = ($63|0)==(0|0);
-       do {
-        if (!($cmp180$i)) {
-         $index$i$172 = ((($v$4$lcssa$i)) + 28|0);
-         $72 = HEAP32[$index$i$172>>2]|0;
-         $arrayidx184$i = (480 + ($72<<2)|0);
-         $73 = HEAP32[$arrayidx184$i>>2]|0;
-         $cmp185$i = ($v$4$lcssa$i|0)==($73|0);
-         if ($cmp185$i) {
-          HEAP32[$arrayidx184$i>>2] = $R$3$i$171;
-          $cond3$i = ($R$3$i$171|0)==(0|0);
-          if ($cond3$i) {
-           $shl192$i = 1 << $72;
-           $neg$i$173 = $shl192$i ^ -1;
-           $74 = HEAP32[(180)>>2]|0;
-           $and194$i = $74 & $neg$i$173;
-           HEAP32[(180)>>2] = $and194$i;
-           break;
-          }
-         } else {
-          $75 = HEAP32[(192)>>2]|0;
-          $cmp198$i = ($63>>>0)<($75>>>0);
-          if ($cmp198$i) {
-           _abort();
-           // unreachable;
-          }
-          $arrayidx204$i = ((($63)) + 16|0);
-          $76 = HEAP32[$arrayidx204$i>>2]|0;
-          $cmp205$i = ($76|0)==($v$4$lcssa$i|0);
-          if ($cmp205$i) {
-           HEAP32[$arrayidx204$i>>2] = $R$3$i$171;
-          } else {
-           $arrayidx212$i = ((($63)) + 20|0);
-           HEAP32[$arrayidx212$i>>2] = $R$3$i$171;
-          }
-          $cmp217$i = ($R$3$i$171|0)==(0|0);
-          if ($cmp217$i) {
-           break;
-          }
-         }
-         $77 = HEAP32[(192)>>2]|0;
-         $cmp221$i = ($R$3$i$171>>>0)<($77>>>0);
-         if ($cmp221$i) {
-          _abort();
-          // unreachable;
-         }
-         $parent226$i = ((($R$3$i$171)) + 24|0);
-         HEAP32[$parent226$i>>2] = $63;
-         $arrayidx228$i = ((($v$4$lcssa$i)) + 16|0);
-         $78 = HEAP32[$arrayidx228$i>>2]|0;
-         $cmp229$i = ($78|0)==(0|0);
-         do {
-          if (!($cmp229$i)) {
-           $cmp233$i = ($78>>>0)<($77>>>0);
-           if ($cmp233$i) {
-            _abort();
-            // unreachable;
-           } else {
-            $arrayidx239$i = ((($R$3$i$171)) + 16|0);
-            HEAP32[$arrayidx239$i>>2] = $78;
-            $parent240$i = ((($78)) + 24|0);
-            HEAP32[$parent240$i>>2] = $R$3$i$171;
-            break;
-           }
-          }
-         } while(0);
-         $arrayidx245$i = ((($v$4$lcssa$i)) + 20|0);
-         $79 = HEAP32[$arrayidx245$i>>2]|0;
-         $cmp246$i = ($79|0)==(0|0);
-         if (!($cmp246$i)) {
-          $80 = HEAP32[(192)>>2]|0;
-          $cmp250$i = ($79>>>0)<($80>>>0);
-          if ($cmp250$i) {
-           _abort();
-           // unreachable;
-          } else {
-           $arrayidx256$i = ((($R$3$i$171)) + 20|0);
-           HEAP32[$arrayidx256$i>>2] = $79;
-           $parent257$i = ((($79)) + 24|0);
-           HEAP32[$parent257$i>>2] = $R$3$i$171;
-           break;
-          }
-         }
-        }
-       } while(0);
-       $cmp265$i = ($rsize$4$lcssa$i>>>0)<(16);
-       do {
-        if ($cmp265$i) {
-         $add268$i = (($rsize$4$lcssa$i) + ($and145))|0;
-         $or270$i = $add268$i | 3;
-         $head271$i = ((($v$4$lcssa$i)) + 4|0);
-         HEAP32[$head271$i>>2] = $or270$i;
-         $add$ptr273$i = (($v$4$lcssa$i) + ($add268$i)|0);
-         $head274$i = ((($add$ptr273$i)) + 4|0);
-         $81 = HEAP32[$head274$i>>2]|0;
-         $or275$i = $81 | 1;
-         HEAP32[$head274$i>>2] = $or275$i;
-        } else {
-         $or278$i = $and145 | 3;
-         $head279$i = ((($v$4$lcssa$i)) + 4|0);
-         HEAP32[$head279$i>>2] = $or278$i;
-         $or280$i = $rsize$4$lcssa$i | 1;
-         $head281$i = ((($add$ptr$i$161)) + 4|0);
-         HEAP32[$head281$i>>2] = $or280$i;
-         $add$ptr282$i = (($add$ptr$i$161) + ($rsize$4$lcssa$i)|0);
-         HEAP32[$add$ptr282$i>>2] = $rsize$4$lcssa$i;
-         $shr283$i = $rsize$4$lcssa$i >>> 3;
-         $cmp284$i = ($rsize$4$lcssa$i>>>0)<(256);
-         if ($cmp284$i) {
-          $shl288$i = $shr283$i << 1;
-          $arrayidx289$i = (216 + ($shl288$i<<2)|0);
-          $82 = HEAP32[44]|0;
-          $shl291$i = 1 << $shr283$i;
-          $and292$i = $82 & $shl291$i;
-          $tobool293$i = ($and292$i|0)==(0);
-          if ($tobool293$i) {
-           $or297$i = $82 | $shl291$i;
-           HEAP32[44] = $or297$i;
-           $$pre$i$177 = ((($arrayidx289$i)) + 8|0);
-           $$pre$phi$i$178Z2D = $$pre$i$177;$F290$0$i = $arrayidx289$i;
-          } else {
-           $83 = ((($arrayidx289$i)) + 8|0);
-           $84 = HEAP32[$83>>2]|0;
-           $85 = HEAP32[(192)>>2]|0;
-           $cmp301$i = ($84>>>0)<($85>>>0);
-           if ($cmp301$i) {
-            _abort();
-            // unreachable;
-           } else {
-            $$pre$phi$i$178Z2D = $83;$F290$0$i = $84;
-           }
-          }
-          HEAP32[$$pre$phi$i$178Z2D>>2] = $add$ptr$i$161;
-          $bk311$i = ((($F290$0$i)) + 12|0);
-          HEAP32[$bk311$i>>2] = $add$ptr$i$161;
-          $fd312$i = ((($add$ptr$i$161)) + 8|0);
-          HEAP32[$fd312$i>>2] = $F290$0$i;
-          $bk313$i = ((($add$ptr$i$161)) + 12|0);
-          HEAP32[$bk313$i>>2] = $arrayidx289$i;
-          break;
-         }
-         $shr318$i = $rsize$4$lcssa$i >>> 8;
-         $cmp319$i = ($shr318$i|0)==(0);
-         if ($cmp319$i) {
-          $I316$0$i = 0;
-         } else {
-          $cmp323$i = ($rsize$4$lcssa$i>>>0)>(16777215);
-          if ($cmp323$i) {
-           $I316$0$i = 31;
-          } else {
-           $sub329$i = (($shr318$i) + 1048320)|0;
-           $shr330$i = $sub329$i >>> 16;
-           $and331$i = $shr330$i & 8;
-           $shl333$i = $shr318$i << $and331$i;
-           $sub334$i = (($shl333$i) + 520192)|0;
-           $shr335$i = $sub334$i >>> 16;
-           $and336$i = $shr335$i & 4;
-           $add337$i = $and336$i | $and331$i;
-           $shl338$i = $shl333$i << $and336$i;
-           $sub339$i = (($shl338$i) + 245760)|0;
-           $shr340$i = $sub339$i >>> 16;
-           $and341$i = $shr340$i & 2;
-           $add342$i = $add337$i | $and341$i;
-           $sub343$i = (14 - ($add342$i))|0;
-           $shl344$i = $shl338$i << $and341$i;
-           $shr345$i = $shl344$i >>> 15;
-           $add346$i = (($sub343$i) + ($shr345$i))|0;
-           $shl347$i = $add346$i << 1;
-           $add348$i = (($add346$i) + 7)|0;
-           $shr349$i = $rsize$4$lcssa$i >>> $add348$i;
-           $and350$i = $shr349$i & 1;
-           $add351$i = $and350$i | $shl347$i;
-           $I316$0$i = $add351$i;
-          }
-         }
-         $arrayidx355$i = (480 + ($I316$0$i<<2)|0);
-         $index356$i = ((($add$ptr$i$161)) + 28|0);
-         HEAP32[$index356$i>>2] = $I316$0$i;
-         $child357$i = ((($add$ptr$i$161)) + 16|0);
-         $arrayidx358$i = ((($child357$i)) + 4|0);
-         HEAP32[$arrayidx358$i>>2] = 0;
-         HEAP32[$child357$i>>2] = 0;
-         $86 = HEAP32[(180)>>2]|0;
-         $shl362$i = 1 << $I316$0$i;
-         $and363$i = $86 & $shl362$i;
-         $tobool364$i = ($and363$i|0)==(0);
-         if ($tobool364$i) {
-          $or368$i = $86 | $shl362$i;
-          HEAP32[(180)>>2] = $or368$i;
-          HEAP32[$arrayidx355$i>>2] = $add$ptr$i$161;
-          $parent369$i = ((($add$ptr$i$161)) + 24|0);
-          HEAP32[$parent369$i>>2] = $arrayidx355$i;
-          $bk370$i = ((($add$ptr$i$161)) + 12|0);
-          HEAP32[$bk370$i>>2] = $add$ptr$i$161;
-          $fd371$i = ((($add$ptr$i$161)) + 8|0);
-          HEAP32[$fd371$i>>2] = $add$ptr$i$161;
-          break;
-         }
-         $87 = HEAP32[$arrayidx355$i>>2]|0;
-         $cmp374$i = ($I316$0$i|0)==(31);
-         $shr378$i = $I316$0$i >>> 1;
-         $sub381$i = (25 - ($shr378$i))|0;
-         $cond383$i = $cmp374$i ? 0 : $sub381$i;
-         $shl384$i = $rsize$4$lcssa$i << $cond383$i;
-         $K373$0$i = $shl384$i;$T$0$i = $87;
-         while(1) {
-          $head386$i = ((($T$0$i)) + 4|0);
-          $88 = HEAP32[$head386$i>>2]|0;
-          $and387$i = $88 & -8;
-          $cmp388$i = ($and387$i|0)==($rsize$4$lcssa$i|0);
-          if ($cmp388$i) {
-           $T$0$i$lcssa = $T$0$i;
-           label = 148;
-           break;
-          }
-          $shr391$i = $K373$0$i >>> 31;
-          $arrayidx394$i = (((($T$0$i)) + 16|0) + ($shr391$i<<2)|0);
-          $shl395$i = $K373$0$i << 1;
-          $89 = HEAP32[$arrayidx394$i>>2]|0;
-          $cmp396$i = ($89|0)==(0|0);
-          if ($cmp396$i) {
-           $T$0$i$lcssa293 = $T$0$i;$arrayidx394$i$lcssa = $arrayidx394$i;
-           label = 145;
-           break;
-          } else {
-           $K373$0$i = $shl395$i;$T$0$i = $89;
-          }
-         }
-         if ((label|0) == 145) {
-          $90 = HEAP32[(192)>>2]|0;
-          $cmp401$i = ($arrayidx394$i$lcssa>>>0)<($90>>>0);
-          if ($cmp401$i) {
-           _abort();
-           // unreachable;
-          } else {
-           HEAP32[$arrayidx394$i$lcssa>>2] = $add$ptr$i$161;
-           $parent406$i = ((($add$ptr$i$161)) + 24|0);
-           HEAP32[$parent406$i>>2] = $T$0$i$lcssa293;
-           $bk407$i = ((($add$ptr$i$161)) + 12|0);
-           HEAP32[$bk407$i>>2] = $add$ptr$i$161;
-           $fd408$i = ((($add$ptr$i$161)) + 8|0);
-           HEAP32[$fd408$i>>2] = $add$ptr$i$161;
-           break;
-          }
-         }
-         else if ((label|0) == 148) {
-          $fd416$i = ((($T$0$i$lcssa)) + 8|0);
-          $91 = HEAP32[$fd416$i>>2]|0;
-          $92 = HEAP32[(192)>>2]|0;
-          $cmp422$i = ($91>>>0)>=($92>>>0);
-          $not$cmp418$i = ($T$0$i$lcssa>>>0)>=($92>>>0);
-          $93 = $cmp422$i & $not$cmp418$i;
-          if ($93) {
-           $bk429$i = ((($91)) + 12|0);
-           HEAP32[$bk429$i>>2] = $add$ptr$i$161;
-           HEAP32[$fd416$i>>2] = $add$ptr$i$161;
-           $fd431$i = ((($add$ptr$i$161)) + 8|0);
-           HEAP32[$fd431$i>>2] = $91;
-           $bk432$i = ((($add$ptr$i$161)) + 12|0);
-           HEAP32[$bk432$i>>2] = $T$0$i$lcssa;
-           $parent433$i = ((($add$ptr$i$161)) + 24|0);
-           HEAP32[$parent433$i>>2] = 0;
-           break;
-          } else {
-           _abort();
-           // unreachable;
-          }
-         }
-        }
-       } while(0);
-       $add$ptr441$i = ((($v$4$lcssa$i)) + 8|0);
-       $retval$0 = $add$ptr441$i;
-       return ($retval$0|0);
-      } else {
-       $nb$0 = $and145;
-      }
-     }
-    }
-   }
-  }
- } while(0);
- $94 = HEAP32[(184)>>2]|0;
- $cmp156 = ($94>>>0)<($nb$0>>>0);
- if (!($cmp156)) {
-  $sub160 = (($94) - ($nb$0))|0;
-  $95 = HEAP32[(196)>>2]|0;
-  $cmp162 = ($sub160>>>0)>(15);
-  if ($cmp162) {
-   $add$ptr166 = (($95) + ($nb$0)|0);
-   HEAP32[(196)>>2] = $add$ptr166;
-   HEAP32[(184)>>2] = $sub160;
-   $or167 = $sub160 | 1;
-   $head168 = ((($add$ptr166)) + 4|0);
-   HEAP32[$head168>>2] = $or167;
-   $add$ptr169 = (($add$ptr166) + ($sub160)|0);
-   HEAP32[$add$ptr169>>2] = $sub160;
-   $or172 = $nb$0 | 3;
-   $head173 = ((($95)) + 4|0);
-   HEAP32[$head173>>2] = $or172;
-  } else {
-   HEAP32[(184)>>2] = 0;
-   HEAP32[(196)>>2] = 0;
-   $or176 = $94 | 3;
-   $head177 = ((($95)) + 4|0);
-   HEAP32[$head177>>2] = $or176;
-   $add$ptr178 = (($95) + ($94)|0);
-   $head179 = ((($add$ptr178)) + 4|0);
-   $96 = HEAP32[$head179>>2]|0;
-   $or180 = $96 | 1;
-   HEAP32[$head179>>2] = $or180;
-  }
-  $add$ptr182 = ((($95)) + 8|0);
-  $retval$0 = $add$ptr182;
-  return ($retval$0|0);
- }
- $97 = HEAP32[(188)>>2]|0;
- $cmp186 = ($97>>>0)>($nb$0>>>0);
- if ($cmp186) {
-  $sub190 = (($97) - ($nb$0))|0;
-  HEAP32[(188)>>2] = $sub190;
-  $98 = HEAP32[(200)>>2]|0;
-  $add$ptr193 = (($98) + ($nb$0)|0);
-  HEAP32[(200)>>2] = $add$ptr193;
-  $or194 = $sub190 | 1;
-  $head195 = ((($add$ptr193)) + 4|0);
-  HEAP32[$head195>>2] = $or194;
-  $or197 = $nb$0 | 3;
-  $head198 = ((($98)) + 4|0);
-  HEAP32[$head198>>2] = $or197;
-  $add$ptr199 = ((($98)) + 8|0);
-  $retval$0 = $add$ptr199;
-  return ($retval$0|0);
- }
- $99 = HEAP32[162]|0;
- $cmp$i$179 = ($99|0)==(0);
- do {
-  if ($cmp$i$179) {
-   $call$i$i = (_sysconf(30)|0);
-   $sub$i$i = (($call$i$i) + -1)|0;
-   $and$i$i = $sub$i$i & $call$i$i;
-   $cmp1$i$i = ($and$i$i|0)==(0);
-   if ($cmp1$i$i) {
-    HEAP32[(656)>>2] = $call$i$i;
-    HEAP32[(652)>>2] = $call$i$i;
-    HEAP32[(660)>>2] = -1;
-    HEAP32[(664)>>2] = -1;
-    HEAP32[(668)>>2] = 0;
-    HEAP32[(620)>>2] = 0;
-    $call6$i$i = (_time((0|0))|0);
-    $xor$i$i = $call6$i$i & -16;
-    $and7$i$i = $xor$i$i ^ 1431655768;
-    HEAP32[162] = $and7$i$i;
-    break;
-   } else {
-    _abort();
-    // unreachable;
-   }
-  }
- } while(0);
- $add$i$180 = (($nb$0) + 48)|0;
- $100 = HEAP32[(656)>>2]|0;
- $sub$i$181 = (($nb$0) + 47)|0;
- $add9$i = (($100) + ($sub$i$181))|0;
- $neg$i$182 = (0 - ($100))|0;
- $and11$i = $add9$i & $neg$i$182;
- $cmp12$i = ($and11$i>>>0)>($nb$0>>>0);
- if (!($cmp12$i)) {
-  $retval$0 = 0;
-  return ($retval$0|0);
- }
- $101 = HEAP32[(616)>>2]|0;
- $cmp15$i = ($101|0)==(0);
- if (!($cmp15$i)) {
-  $102 = HEAP32[(608)>>2]|0;
-  $add17$i$183 = (($102) + ($and11$i))|0;
-  $cmp19$i = ($add17$i$183>>>0)<=($102>>>0);
-  $cmp21$i = ($add17$i$183>>>0)>($101>>>0);
-  $or$cond1$i$184 = $cmp19$i | $cmp21$i;
-  if ($or$cond1$i$184) {
-   $retval$0 = 0;
-   return ($retval$0|0);
-  }
- }
- $103 = HEAP32[(620)>>2]|0;
- $and29$i = $103 & 4;
- $tobool30$i = ($and29$i|0)==(0);
- L257: do {
-  if ($tobool30$i) {
-   $104 = HEAP32[(200)>>2]|0;
-   $cmp32$i$185 = ($104|0)==(0|0);
-   L259: do {
-    if ($cmp32$i$185) {
-     label = 173;
-    } else {
-     $sp$0$i$i = (624);
-     while(1) {
-      $105 = HEAP32[$sp$0$i$i>>2]|0;
-      $cmp$i$9$i = ($105>>>0)>($104>>>0);
-      if (!($cmp$i$9$i)) {
-       $size$i$i = ((($sp$0$i$i)) + 4|0);
-       $106 = HEAP32[$size$i$i>>2]|0;
-       $add$ptr$i$i = (($105) + ($106)|0);
-       $cmp2$i$i = ($add$ptr$i$i>>>0)>($104>>>0);
-       if ($cmp2$i$i) {
-        $base$i$i$lcssa = $sp$0$i$i;$size$i$i$lcssa = $size$i$i;
-        break;
-       }
-      }
-      $next$i$i = ((($sp$0$i$i)) + 8|0);
-      $107 = HEAP32[$next$i$i>>2]|0;
-      $cmp3$i$i = ($107|0)==(0|0);
-      if ($cmp3$i$i) {
-       label = 173;
-       break L259;
-      } else {
-       $sp$0$i$i = $107;
-      }
-     }
-     $112 = HEAP32[(188)>>2]|0;
-     $add77$i = (($add9$i) - ($112))|0;
-     $and80$i = $add77$i & $neg$i$182;
-     $cmp81$i$191 = ($and80$i>>>0)<(2147483647);
-     if ($cmp81$i$191) {
-      $call83$i = (_sbrk(($and80$i|0))|0);
-      $113 = HEAP32[$base$i$i$lcssa>>2]|0;
-      $114 = HEAP32[$size$i$i$lcssa>>2]|0;
-      $add$ptr$i$193 = (($113) + ($114)|0);
-      $cmp85$i = ($call83$i|0)==($add$ptr$i$193|0);
-      if ($cmp85$i) {
-       $cmp89$i = ($call83$i|0)==((-1)|0);
-       if (!($cmp89$i)) {
-        $tbase$796$i = $call83$i;$tsize$795$i = $and80$i;
-        label = 193;
-        break L257;
-       }
-      } else {
-       $br$2$ph$i = $call83$i;$ssize$2$ph$i = $and80$i;
-       label = 183;
-      }
-     }
-    }
-   } while(0);
-   do {
-    if ((label|0) == 173) {
-     $call37$i = (_sbrk(0)|0);
-     $cmp38$i = ($call37$i|0)==((-1)|0);
-     if (!($cmp38$i)) {
-      $108 = $call37$i;
-      $109 = HEAP32[(652)>>2]|0;
-      $sub41$i = (($109) + -1)|0;
-      $and42$i = $sub41$i & $108;
-      $cmp43$i = ($and42$i|0)==(0);
-      if ($cmp43$i) {
-       $ssize$0$i = $and11$i;
-      } else {
-       $add46$i = (($sub41$i) + ($108))|0;
-       $neg48$i = (0 - ($109))|0;
-       $and49$i = $add46$i & $neg48$i;
-       $sub50$i = (($and11$i) - ($108))|0;
-       $add51$i = (($sub50$i) + ($and49$i))|0;
-       $ssize$0$i = $add51$i;
-      }
-      $110 = HEAP32[(608)>>2]|0;
-      $add54$i = (($110) + ($ssize$0$i))|0;
-      $cmp55$i$187 = ($ssize$0$i>>>0)>($nb$0>>>0);
-      $cmp57$i$188 = ($ssize$0$i>>>0)<(2147483647);
-      $or$cond$i$189 = $cmp55$i$187 & $cmp57$i$188;
-      if ($or$cond$i$189) {
-       $111 = HEAP32[(616)>>2]|0;
-       $cmp60$i = ($111|0)==(0);
-       if (!($cmp60$i)) {
-        $cmp63$i = ($add54$i>>>0)<=($110>>>0);
-        $cmp66$i$190 = ($add54$i>>>0)>($111>>>0);
-        $or$cond2$i = $cmp63$i | $cmp66$i$190;
-        if ($or$cond2$i) {
-         break;
-        }
-       }
-       $call68$i = (_sbrk(($ssize$0$i|0))|0);
-       $cmp69$i = ($call68$i|0)==($call37$i|0);
-       if ($cmp69$i) {
-        $tbase$796$i = $call37$i;$tsize$795$i = $ssize$0$i;
-        label = 193;
-        break L257;
-       } else {
-        $br$2$ph$i = $call68$i;$ssize$2$ph$i = $ssize$0$i;
-        label = 183;
-       }
-      }
-     }
-    }
-   } while(0);
-   L279: do {
-    if ((label|0) == 183) {
-     $sub112$i = (0 - ($ssize$2$ph$i))|0;
-     $cmp91$i = ($br$2$ph$i|0)!=((-1)|0);
-     $cmp93$i = ($ssize$2$ph$i>>>0)<(2147483647);
-     $or$cond5$i = $cmp93$i & $cmp91$i;
-     $cmp96$i = ($add$i$180>>>0)>($ssize$2$ph$i>>>0);
-     $or$cond3$i = $cmp96$i & $or$cond5$i;
-     do {
-      if ($or$cond3$i) {
-       $115 = HEAP32[(656)>>2]|0;
-       $sub99$i = (($sub$i$181) - ($ssize$2$ph$i))|0;
-       $add101$i = (($sub99$i) + ($115))|0;
-       $neg103$i = (0 - ($115))|0;
-       $and104$i = $add101$i & $neg103$i;
-       $cmp105$i = ($and104$i>>>0)<(2147483647);
-       if ($cmp105$i) {
-        $call107$i = (_sbrk(($and104$i|0))|0);
-        $cmp108$i = ($call107$i|0)==((-1)|0);
-        if ($cmp108$i) {
-         (_sbrk(($sub112$i|0))|0);
-         break L279;
-        } else {
-         $add110$i = (($and104$i) + ($ssize$2$ph$i))|0;
-         $ssize$5$i = $add110$i;
-         break;
-        }
-       } else {
-        $ssize$5$i = $ssize$2$ph$i;
-       }
-      } else {
-       $ssize$5$i = $ssize$2$ph$i;
-      }
-     } while(0);
-     $cmp118$i = ($br$2$ph$i|0)==((-1)|0);
-     if (!($cmp118$i)) {
-      $tbase$796$i = $br$2$ph$i;$tsize$795$i = $ssize$5$i;
-      label = 193;
-      break L257;
-     }
-    }
-   } while(0);
-   $116 = HEAP32[(620)>>2]|0;
-   $or$i$195 = $116 | 4;
-   HEAP32[(620)>>2] = $or$i$195;
-   label = 190;
-  } else {
-   label = 190;
-  }
- } while(0);
- if ((label|0) == 190) {
-  $cmp127$i = ($and11$i>>>0)<(2147483647);
-  if ($cmp127$i) {
-   $call131$i = (_sbrk(($and11$i|0))|0);
-   $call132$i = (_sbrk(0)|0);
-   $cmp133$i$196 = ($call131$i|0)!=((-1)|0);
-   $cmp135$i = ($call132$i|0)!=((-1)|0);
-   $or$cond4$i = $cmp133$i$196 & $cmp135$i;
-   $cmp137$i$197 = ($call131$i>>>0)<($call132$i>>>0);
-   $or$cond7$i = $cmp137$i$197 & $or$cond4$i;
-   if ($or$cond7$i) {
-    $sub$ptr$lhs$cast$i = $call132$i;
-    $sub$ptr$rhs$cast$i = $call131$i;
-    $sub$ptr$sub$i = (($sub$ptr$lhs$cast$i) - ($sub$ptr$rhs$cast$i))|0;
-    $add140$i = (($nb$0) + 40)|0;
-    $cmp141$not$i = ($sub$ptr$sub$i>>>0)>($add140$i>>>0);
-    if ($cmp141$not$i) {
-     $tbase$796$i = $call131$i;$tsize$795$i = $sub$ptr$sub$i;
-     label = 193;
-    }
-   }
-  }
- }
- if ((label|0) == 193) {
-  $117 = HEAP32[(608)>>2]|0;
-  $add150$i = (($117) + ($tsize$795$i))|0;
-  HEAP32[(608)>>2] = $add150$i;
-  $118 = HEAP32[(612)>>2]|0;
-  $cmp151$i = ($add150$i>>>0)>($118>>>0);
-  if ($cmp151$i) {
-   HEAP32[(612)>>2] = $add150$i;
-  }
-  $119 = HEAP32[(200)>>2]|0;
-  $cmp157$i = ($119|0)==(0|0);
-  do {
-   if ($cmp157$i) {
-    $120 = HEAP32[(192)>>2]|0;
-    $cmp159$i$199 = ($120|0)==(0|0);
-    $cmp162$i$200 = ($tbase$796$i>>>0)<($120>>>0);
-    $or$cond8$i = $cmp159$i$199 | $cmp162$i$200;
-    if ($or$cond8$i) {
-     HEAP32[(192)>>2] = $tbase$796$i;
-    }
-    HEAP32[(624)>>2] = $tbase$796$i;
-    HEAP32[(628)>>2] = $tsize$795$i;
-    HEAP32[(636)>>2] = 0;
-    $121 = HEAP32[162]|0;
-    HEAP32[(212)>>2] = $121;
-    HEAP32[(208)>>2] = -1;
-    $i$01$i$i = 0;
-    while(1) {
-     $shl$i$i = $i$01$i$i << 1;
-     $arrayidx$i$i = (216 + ($shl$i$i<<2)|0);
-     $122 = ((($arrayidx$i$i)) + 12|0);
-     HEAP32[$122>>2] = $arrayidx$i$i;
-     $123 = ((($arrayidx$i$i)) + 8|0);
-     HEAP32[$123>>2] = $arrayidx$i$i;
-     $inc$i$i = (($i$01$i$i) + 1)|0;
-     $exitcond$i$i = ($inc$i$i|0)==(32);
-     if ($exitcond$i$i) {
-      break;
-     } else {
-      $i$01$i$i = $inc$i$i;
-     }
-    }
-    $sub172$i = (($tsize$795$i) + -40)|0;
-    $add$ptr$i$11$i = ((($tbase$796$i)) + 8|0);
-    $124 = $add$ptr$i$11$i;
-    $and$i$12$i = $124 & 7;
-    $cmp$i$13$i = ($and$i$12$i|0)==(0);
-    $125 = (0 - ($124))|0;
-    $and3$i$i = $125 & 7;
-    $cond$i$i = $cmp$i$13$i ? 0 : $and3$i$i;
-    $add$ptr4$i$i = (($tbase$796$i) + ($cond$i$i)|0);
-    $sub5$i$i = (($sub172$i) - ($cond$i$i))|0;
-    HEAP32[(200)>>2] = $add$ptr4$i$i;
-    HEAP32[(188)>>2] = $sub5$i$i;
-    $or$i$i = $sub5$i$i | 1;
-    $head$i$i = ((($add$ptr4$i$i)) + 4|0);
-    HEAP32[$head$i$i>>2] = $or$i$i;
-    $add$ptr6$i$i = (($add$ptr4$i$i) + ($sub5$i$i)|0);
-    $head7$i$i = ((($add$ptr6$i$i)) + 4|0);
-    HEAP32[$head7$i$i>>2] = 40;
-    $126 = HEAP32[(664)>>2]|0;
-    HEAP32[(204)>>2] = $126;
-   } else {
-    $sp$0108$i = (624);
-    while(1) {
-     $127 = HEAP32[$sp$0108$i>>2]|0;
-     $size188$i = ((($sp$0108$i)) + 4|0);
-     $128 = HEAP32[$size188$i>>2]|0;
-     $add$ptr189$i = (($127) + ($128)|0);
-     $cmp190$i = ($tbase$796$i|0)==($add$ptr189$i|0);
-     if ($cmp190$i) {
-      $$lcssa = $127;$$lcssa290 = $128;$size188$i$lcssa = $size188$i;$sp$0108$i$lcssa = $sp$0108$i;
-      label = 203;
-      break;
-     }
-     $next$i = ((($sp$0108$i)) + 8|0);
-     $129 = HEAP32[$next$i>>2]|0;
-     $cmp186$i = ($129|0)==(0|0);
-     if ($cmp186$i) {
-      break;
-     } else {
-      $sp$0108$i = $129;
-     }
-    }
-    if ((label|0) == 203) {
-     $sflags193$i = ((($sp$0108$i$lcssa)) + 12|0);
-     $130 = HEAP32[$sflags193$i>>2]|0;
-     $and194$i$204 = $130 & 8;
-     $tobool195$i = ($and194$i$204|0)==(0);
-     if ($tobool195$i) {
-      $cmp203$i = ($119>>>0)>=($$lcssa>>>0);
-      $cmp209$i = ($119>>>0)<($tbase$796$i>>>0);
-      $or$cond98$i = $cmp209$i & $cmp203$i;
-      if ($or$cond98$i) {
-       $add212$i = (($$lcssa290) + ($tsize$795$i))|0;
-       HEAP32[$size188$i$lcssa>>2] = $add212$i;
-       $131 = HEAP32[(188)>>2]|0;
-       $add$ptr$i$21$i = ((($119)) + 8|0);
-       $132 = $add$ptr$i$21$i;
-       $and$i$22$i = $132 & 7;
-       $cmp$i$23$i = ($and$i$22$i|0)==(0);
-       $133 = (0 - ($132))|0;
-       $and3$i$24$i = $133 & 7;
-       $cond$i$25$i = $cmp$i$23$i ? 0 : $and3$i$24$i;
-       $add$ptr4$i$26$i = (($119) + ($cond$i$25$i)|0);
-       $add215$i = (($tsize$795$i) - ($cond$i$25$i))|0;
-       $sub5$i$27$i = (($add215$i) + ($131))|0;
-       HEAP32[(200)>>2] = $add$ptr4$i$26$i;
-       HEAP32[(188)>>2] = $sub5$i$27$i;
-       $or$i$28$i = $sub5$i$27$i | 1;
-       $head$i$29$i = ((($add$ptr4$i$26$i)) + 4|0);
-       HEAP32[$head$i$29$i>>2] = $or$i$28$i;
-       $add$ptr6$i$30$i = (($add$ptr4$i$26$i) + ($sub5$i$27$i)|0);
-       $head7$i$31$i = ((($add$ptr6$i$30$i)) + 4|0);
-       HEAP32[$head7$i$31$i>>2] = 40;
-       $134 = HEAP32[(664)>>2]|0;
-       HEAP32[(204)>>2] = $134;
-       break;
-      }
-     }
-    }
-    $135 = HEAP32[(192)>>2]|0;
-    $cmp218$i = ($tbase$796$i>>>0)<($135>>>0);
-    if ($cmp218$i) {
-     HEAP32[(192)>>2] = $tbase$796$i;
-     $150 = $tbase$796$i;
-    } else {
-     $150 = $135;
-    }
-    $add$ptr227$i = (($tbase$796$i) + ($tsize$795$i)|0);
-    $sp$1107$i = (624);
-    while(1) {
-     $136 = HEAP32[$sp$1107$i>>2]|0;
-     $cmp228$i = ($136|0)==($add$ptr227$i|0);
-     if ($cmp228$i) {
-      $base226$i$lcssa = $sp$1107$i;$sp$1107$i$lcssa = $sp$1107$i;
-      label = 211;
-      break;
-     }
-     $next231$i = ((($sp$1107$i)) + 8|0);
-     $137 = HEAP32[$next231$i>>2]|0;
-     $cmp224$i = ($137|0)==(0|0);
-     if ($cmp224$i) {
-      $sp$0$i$i$i = (624);
-      break;
-     } else {
-      $sp$1107$i = $137;
-     }
-    }
-    if ((label|0) == 211) {
-     $sflags235$i = ((($sp$1107$i$lcssa)) + 12|0);
-     $138 = HEAP32[$sflags235$i>>2]|0;
-     $and236$i = $138 & 8;
-     $tobool237$i = ($and236$i|0)==(0);
-     if ($tobool237$i) {
-      HEAP32[$base226$i$lcssa>>2] = $tbase$796$i;
-      $size245$i = ((($sp$1107$i$lcssa)) + 4|0);
-      $139 = HEAP32[$size245$i>>2]|0;
-      $add246$i = (($139) + ($tsize$795$i))|0;
-      HEAP32[$size245$i>>2] = $add246$i;
-      $add$ptr$i$32$i = ((($tbase$796$i)) + 8|0);
-      $140 = $add$ptr$i$32$i;
-      $and$i$33$i = $140 & 7;
-      $cmp$i$34$i = ($and$i$33$i|0)==(0);
-      $141 = (0 - ($140))|0;
-      $and3$i$35$i = $141 & 7;
-      $cond$i$36$i = $cmp$i$34$i ? 0 : $and3$i$35$i;
-      $add$ptr4$i$37$i = (($tbase$796$i) + ($cond$i$36$i)|0);
-      $add$ptr5$i$i = ((($add$ptr227$i)) + 8|0);
-      $142 = $add$ptr5$i$i;
-      $and6$i$38$i = $142 & 7;
-      $cmp7$i$i = ($and6$i$38$i|0)==(0);
-      $143 = (0 - ($142))|0;
-      $and13$i$i = $143 & 7;
-      $cond15$i$i = $cmp7$i$i ? 0 : $and13$i$i;
-      $add$ptr16$i$i = (($add$ptr227$i) + ($cond15$i$i)|0);
-      $sub$ptr$lhs$cast$i$39$i = $add$ptr16$i$i;
-      $sub$ptr$rhs$cast$i$40$i = $add$ptr4$i$37$i;
-      $sub$ptr$sub$i$41$i = (($sub$ptr$lhs$cast$i$39$i) - ($sub$ptr$rhs$cast$i$40$i))|0;
-      $add$ptr17$i$i = (($add$ptr4$i$37$i) + ($nb$0)|0);
-      $sub18$i$i = (($sub$ptr$sub$i$41$i) - ($nb$0))|0;
-      $or19$i$i = $nb$0 | 3;
-      $head$i$42$i = ((($add$ptr4$i$37$i)) + 4|0);
-      HEAP32[$head$i$42$i>>2] = $or19$i$i;
-      $cmp20$i$i = ($add$ptr16$i$i|0)==($119|0);
-      do {
-       if ($cmp20$i$i) {
-        $144 = HEAP32[(188)>>2]|0;
-        $add$i$i = (($144) + ($sub18$i$i))|0;
-        HEAP32[(188)>>2] = $add$i$i;
-        HEAP32[(200)>>2] = $add$ptr17$i$i;
-        $or22$i$i = $add$i$i | 1;
-        $head23$i$i = ((($add$ptr17$i$i)) + 4|0);
-        HEAP32[$head23$i$i>>2] = $or22$i$i;
-       } else {
-        $145 = HEAP32[(196)>>2]|0;
-        $cmp24$i$i = ($add$ptr16$i$i|0)==($145|0);
-        if ($cmp24$i$i) {
-         $146 = HEAP32[(184)>>2]|0;
-         $add26$i$i = (($146) + ($sub18$i$i))|0;
-         HEAP32[(184)>>2] = $add26$i$i;
-         HEAP32[(196)>>2] = $add$ptr17$i$i;
-         $or28$i$i = $add26$i$i | 1;
-         $head29$i$i = ((($add$ptr17$i$i)) + 4|0);
-         HEAP32[$head29$i$i>>2] = $or28$i$i;
-         $add$ptr30$i$i = (($add$ptr17$i$i) + ($add26$i$i)|0);
-         HEAP32[$add$ptr30$i$i>>2] = $add26$i$i;
-         break;
-        }
-        $head32$i$i = ((($add$ptr16$i$i)) + 4|0);
-        $147 = HEAP32[$head32$i$i>>2]|0;
-        $and33$i$i = $147 & 3;
-        $cmp34$i$i = ($and33$i$i|0)==(1);
-        if ($cmp34$i$i) {
-         $and37$i$i = $147 & -8;
-         $shr$i$45$i = $147 >>> 3;
-         $cmp38$i$i = ($147>>>0)<(256);
-         L331: do {
-          if ($cmp38$i$i) {
-           $fd$i$i = ((($add$ptr16$i$i)) + 8|0);
-           $148 = HEAP32[$fd$i$i>>2]|0;
-           $bk$i$46$i = ((($add$ptr16$i$i)) + 12|0);
-           $149 = HEAP32[$bk$i$46$i>>2]|0;
-           $shl$i$47$i = $shr$i$45$i << 1;
-           $arrayidx$i$48$i = (216 + ($shl$i$47$i<<2)|0);
-           $cmp41$i$i = ($148|0)==($arrayidx$i$48$i|0);
-           do {
-            if (!($cmp41$i$i)) {
-             $cmp42$i$i = ($148>>>0)<($150>>>0);
-             if ($cmp42$i$i) {
-              _abort();
-              // unreachable;
-             }
-             $bk43$i$i = ((($148)) + 12|0);
-             $151 = HEAP32[$bk43$i$i>>2]|0;
-             $cmp44$i$i = ($151|0)==($add$ptr16$i$i|0);
-             if ($cmp44$i$i) {
-              break;
-             }
-             _abort();
-             // unreachable;
-            }
-           } while(0);
-           $cmp46$i$49$i = ($149|0)==($148|0);
-           if ($cmp46$i$49$i) {
-            $shl48$i$i = 1 << $shr$i$45$i;
-            $neg$i$i = $shl48$i$i ^ -1;
-            $152 = HEAP32[44]|0;
-            $and49$i$i = $152 & $neg$i$i;
-            HEAP32[44] = $and49$i$i;
-            break;
-           }
-           $cmp54$i$i = ($149|0)==($arrayidx$i$48$i|0);
-           do {
-            if ($cmp54$i$i) {
-             $$pre5$i$i = ((($149)) + 8|0);
-             $fd68$pre$phi$i$iZ2D = $$pre5$i$i;
-            } else {
-             $cmp57$i$i = ($149>>>0)<($150>>>0);
-             if ($cmp57$i$i) {
-              _abort();
-              // unreachable;
-             }
-             $fd59$i$i = ((($149)) + 8|0);
-             $153 = HEAP32[$fd59$i$i>>2]|0;
-             $cmp60$i$i = ($153|0)==($add$ptr16$i$i|0);
-             if ($cmp60$i$i) {
-              $fd68$pre$phi$i$iZ2D = $fd59$i$i;
-              break;
-             }
-             _abort();
-             // unreachable;
-            }
-           } while(0);
-           $bk67$i$i = ((($148)) + 12|0);
-           HEAP32[$bk67$i$i>>2] = $149;
-           HEAP32[$fd68$pre$phi$i$iZ2D>>2] = $148;
-          } else {
-           $parent$i$51$i = ((($add$ptr16$i$i)) + 24|0);
-           $154 = HEAP32[$parent$i$51$i>>2]|0;
-           $bk74$i$i = ((($add$ptr16$i$i)) + 12|0);
-           $155 = HEAP32[$bk74$i$i>>2]|0;
-           $cmp75$i$i = ($155|0)==($add$ptr16$i$i|0);
-           do {
-            if ($cmp75$i$i) {
-             $child$i$i = ((($add$ptr16$i$i)) + 16|0);
-             $arrayidx96$i$i = ((($child$i$i)) + 4|0);
-             $159 = HEAP32[$arrayidx96$i$i>>2]|0;
-             $cmp97$i$i = ($159|0)==(0|0);
-             if ($cmp97$i$i) {
-              $160 = HEAP32[$child$i$i>>2]|0;
-              $cmp100$i$i = ($160|0)==(0|0);
-              if ($cmp100$i$i) {
-               $R$3$i$i = 0;
-               break;
-              } else {
-               $R$1$i$i = $160;$RP$1$i$i = $child$i$i;
-              }
-             } else {
-              $R$1$i$i = $159;$RP$1$i$i = $arrayidx96$i$i;
-             }
-             while(1) {
-              $arrayidx103$i$i = ((($R$1$i$i)) + 20|0);
-              $161 = HEAP32[$arrayidx103$i$i>>2]|0;
-              $cmp104$i$i = ($161|0)==(0|0);
-              if (!($cmp104$i$i)) {
-               $R$1$i$i = $161;$RP$1$i$i = $arrayidx103$i$i;
-               continue;
-              }
-              $arrayidx107$i$i = ((($R$1$i$i)) + 16|0);
-              $162 = HEAP32[$arrayidx107$i$i>>2]|0;
-              $cmp108$i$i = ($162|0)==(0|0);
-              if ($cmp108$i$i) {
-               $R$1$i$i$lcssa = $R$1$i$i;$RP$1$i$i$lcssa = $RP$1$i$i;
-               break;
-              } else {
-               $R$1$i$i = $162;$RP$1$i$i = $arrayidx107$i$i;
-              }
-             }
-             $cmp112$i$i = ($RP$1$i$i$lcssa>>>0)<($150>>>0);
-             if ($cmp112$i$i) {
-              _abort();
-              // unreachable;
-             } else {
-              HEAP32[$RP$1$i$i$lcssa>>2] = 0;
-              $R$3$i$i = $R$1$i$i$lcssa;
-              break;
-             }
-            } else {
-             $fd78$i$i = ((($add$ptr16$i$i)) + 8|0);
-             $156 = HEAP32[$fd78$i$i>>2]|0;
-             $cmp81$i$i = ($156>>>0)<($150>>>0);
-             if ($cmp81$i$i) {
-              _abort();
-              // unreachable;
-             }
-             $bk82$i$i = ((($156)) + 12|0);
-             $157 = HEAP32[$bk82$i$i>>2]|0;
-             $cmp83$i$i = ($157|0)==($add$ptr16$i$i|0);
-             if (!($cmp83$i$i)) {
-              _abort();
-              // unreachable;
-             }
-             $fd85$i$i = ((($155)) + 8|0);
-             $158 = HEAP32[$fd85$i$i>>2]|0;
-             $cmp86$i$i = ($158|0)==($add$ptr16$i$i|0);
-             if ($cmp86$i$i) {
-              HEAP32[$bk82$i$i>>2] = $155;
-              HEAP32[$fd85$i$i>>2] = $156;
-              $R$3$i$i = $155;
-              break;
-             } else {
-              _abort();
-              // unreachable;
-             }
-            }
-           } while(0);
-           $cmp120$i$53$i = ($154|0)==(0|0);
-           if ($cmp120$i$53$i) {
-            break;
-           }
-           $index$i$54$i = ((($add$ptr16$i$i)) + 28|0);
-           $163 = HEAP32[$index$i$54$i>>2]|0;
-           $arrayidx123$i$i = (480 + ($163<<2)|0);
-           $164 = HEAP32[$arrayidx123$i$i>>2]|0;
-           $cmp124$i$i = ($add$ptr16$i$i|0)==($164|0);
-           do {
-            if ($cmp124$i$i) {
-             HEAP32[$arrayidx123$i$i>>2] = $R$3$i$i;
-             $cond2$i$i = ($R$3$i$i|0)==(0|0);
-             if (!($cond2$i$i)) {
-              break;
-             }
-             $shl131$i$i = 1 << $163;
-             $neg132$i$i = $shl131$i$i ^ -1;
-             $165 = HEAP32[(180)>>2]|0;
-             $and133$i$i = $165 & $neg132$i$i;
-             HEAP32[(180)>>2] = $and133$i$i;
-             break L331;
-            } else {
-             $166 = HEAP32[(192)>>2]|0;
-             $cmp137$i$i = ($154>>>0)<($166>>>0);
-             if ($cmp137$i$i) {
-              _abort();
-              // unreachable;
-             }
-             $arrayidx143$i$i = ((($154)) + 16|0);
-             $167 = HEAP32[$arrayidx143$i$i>>2]|0;
-             $cmp144$i$i = ($167|0)==($add$ptr16$i$i|0);
-             if ($cmp144$i$i) {
-              HEAP32[$arrayidx143$i$i>>2] = $R$3$i$i;
-             } else {
-              $arrayidx151$i$i = ((($154)) + 20|0);
-              HEAP32[$arrayidx151$i$i>>2] = $R$3$i$i;
-             }
-             $cmp156$i$i = ($R$3$i$i|0)==(0|0);
-             if ($cmp156$i$i) {
-              break L331;
-             }
-            }
-           } while(0);
-           $168 = HEAP32[(192)>>2]|0;
-           $cmp160$i$i = ($R$3$i$i>>>0)<($168>>>0);
-           if ($cmp160$i$i) {
-            _abort();
-            // unreachable;
-           }
-           $parent165$i$i = ((($R$3$i$i)) + 24|0);
-           HEAP32[$parent165$i$i>>2] = $154;
-           $child166$i$i = ((($add$ptr16$i$i)) + 16|0);
-           $169 = HEAP32[$child166$i$i>>2]|0;
-           $cmp168$i$i = ($169|0)==(0|0);
-           do {
-            if (!($cmp168$i$i)) {
-             $cmp172$i$i = ($169>>>0)<($168>>>0);
-             if ($cmp172$i$i) {
-              _abort();
-              // unreachable;
-             } else {
-              $arrayidx178$i$i = ((($R$3$i$i)) + 16|0);
-              HEAP32[$arrayidx178$i$i>>2] = $169;
-              $parent179$i$i = ((($169)) + 24|0);
-              HEAP32[$parent179$i$i>>2] = $R$3$i$i;
-              break;
-             }
-            }
-           } while(0);
-           $arrayidx184$i$i = ((($child166$i$i)) + 4|0);
-           $170 = HEAP32[$arrayidx184$i$i>>2]|0;
-           $cmp185$i$i = ($170|0)==(0|0);
-           if ($cmp185$i$i) {
-            break;
-           }
-           $171 = HEAP32[(192)>>2]|0;
-           $cmp189$i$i = ($170>>>0)<($171>>>0);
-           if ($cmp189$i$i) {
-            _abort();
-            // unreachable;
-           } else {
-            $arrayidx195$i$i = ((($R$3$i$i)) + 20|0);
-            HEAP32[$arrayidx195$i$i>>2] = $170;
-            $parent196$i$i = ((($170)) + 24|0);
-            HEAP32[$parent196$i$i>>2] = $R$3$i$i;
-            break;
-           }
-          }
-         } while(0);
-         $add$ptr205$i$i = (($add$ptr16$i$i) + ($and37$i$i)|0);
-         $add206$i$i = (($and37$i$i) + ($sub18$i$i))|0;
-         $oldfirst$0$i$i = $add$ptr205$i$i;$qsize$0$i$i = $add206$i$i;
-        } else {
-         $oldfirst$0$i$i = $add$ptr16$i$i;$qsize$0$i$i = $sub18$i$i;
-        }
-        $head208$i$i = ((($oldfirst$0$i$i)) + 4|0);
-        $172 = HEAP32[$head208$i$i>>2]|0;
-        $and209$i$i = $172 & -2;
-        HEAP32[$head208$i$i>>2] = $and209$i$i;
-        $or210$i$i = $qsize$0$i$i | 1;
-        $head211$i$i = ((($add$ptr17$i$i)) + 4|0);
-        HEAP32[$head211$i$i>>2] = $or210$i$i;
-        $add$ptr212$i$i = (($add$ptr17$i$i) + ($qsize$0$i$i)|0);
-        HEAP32[$add$ptr212$i$i>>2] = $qsize$0$i$i;
-        $shr214$i$i = $qsize$0$i$i >>> 3;
-        $cmp215$i$i = ($qsize$0$i$i>>>0)<(256);
-        if ($cmp215$i$i) {
-         $shl221$i$i = $shr214$i$i << 1;
-         $arrayidx223$i$i = (216 + ($shl221$i$i<<2)|0);
-         $173 = HEAP32[44]|0;
-         $shl226$i$i = 1 << $shr214$i$i;
-         $and227$i$i = $173 & $shl226$i$i;
-         $tobool228$i$i = ($and227$i$i|0)==(0);
-         do {
-          if ($tobool228$i$i) {
-           $or232$i$i = $173 | $shl226$i$i;
-           HEAP32[44] = $or232$i$i;
-           $$pre$i$56$i = ((($arrayidx223$i$i)) + 8|0);
-           $$pre$phi$i$57$iZ2D = $$pre$i$56$i;$F224$0$i$i = $arrayidx223$i$i;
-          } else {
-           $174 = ((($arrayidx223$i$i)) + 8|0);
-           $175 = HEAP32[$174>>2]|0;
-           $176 = HEAP32[(192)>>2]|0;
-           $cmp236$i$i = ($175>>>0)<($176>>>0);
-           if (!($cmp236$i$i)) {
-            $$pre$phi$i$57$iZ2D = $174;$F224$0$i$i = $175;
-            break;
-           }
-           _abort();
-           // unreachable;
-          }
-         } while(0);
-         HEAP32[$$pre$phi$i$57$iZ2D>>2] = $add$ptr17$i$i;
-         $bk246$i$i = ((($F224$0$i$i)) + 12|0);
-         HEAP32[$bk246$i$i>>2] = $add$ptr17$i$i;
-         $fd247$i$i = ((($add$ptr17$i$i)) + 8|0);
-         HEAP32[$fd247$i$i>>2] = $F224$0$i$i;
-         $bk248$i$i = ((($add$ptr17$i$i)) + 12|0);
-         HEAP32[$bk248$i$i>>2] = $arrayidx223$i$i;
-         break;
-        }
-        $shr253$i$i = $qsize$0$i$i >>> 8;
-        $cmp254$i$i = ($shr253$i$i|0)==(0);
-        do {
-         if ($cmp254$i$i) {
-          $I252$0$i$i = 0;
-         } else {
-          $cmp258$i$i = ($qsize$0$i$i>>>0)>(16777215);
-          if ($cmp258$i$i) {
-           $I252$0$i$i = 31;
-           break;
-          }
-          $sub262$i$i = (($shr253$i$i) + 1048320)|0;
-          $shr263$i$i = $sub262$i$i >>> 16;
-          $and264$i$i = $shr263$i$i & 8;
-          $shl265$i$i = $shr253$i$i << $and264$i$i;
-          $sub266$i$i = (($shl265$i$i) + 520192)|0;
-          $shr267$i$i = $sub266$i$i >>> 16;
-          $and268$i$i = $shr267$i$i & 4;
-          $add269$i$i = $and268$i$i | $and264$i$i;
-          $shl270$i$i = $shl265$i$i << $and268$i$i;
-          $sub271$i$i = (($shl270$i$i) + 245760)|0;
-          $shr272$i$i = $sub271$i$i >>> 16;
-          $and273$i$i = $shr272$i$i & 2;
-          $add274$i$i = $add269$i$i | $and273$i$i;
-          $sub275$i$i = (14 - ($add274$i$i))|0;
-          $shl276$i$i = $shl270$i$i << $and273$i$i;
-          $shr277$i$i = $shl276$i$i >>> 15;
-          $add278$i$i = (($sub275$i$i) + ($shr277$i$i))|0;
-          $shl279$i$i = $add278$i$i << 1;
-          $add280$i$i = (($add278$i$i) + 7)|0;
-          $shr281$i$i = $qsize$0$i$i >>> $add280$i$i;
-          $and282$i$i = $shr281$i$i & 1;
-          $add283$i$i = $and282$i$i | $shl279$i$i;
-          $I252$0$i$i = $add283$i$i;
-         }
-        } while(0);
-        $arrayidx287$i$i = (480 + ($I252$0$i$i<<2)|0);
-        $index288$i$i = ((($add$ptr17$i$i)) + 28|0);
-        HEAP32[$index288$i$i>>2] = $I252$0$i$i;
-        $child289$i$i = ((($add$ptr17$i$i)) + 16|0);
-        $arrayidx290$i$i = ((($child289$i$i)) + 4|0);
-        HEAP32[$arrayidx290$i$i>>2] = 0;
-        HEAP32[$child289$i$i>>2] = 0;
-        $177 = HEAP32[(180)>>2]|0;
-        $shl294$i$i = 1 << $I252$0$i$i;
-        $and295$i$i = $177 & $shl294$i$i;
-        $tobool296$i$i = ($and295$i$i|0)==(0);
-        if ($tobool296$i$i) {
-         $or300$i$i = $177 | $shl294$i$i;
-         HEAP32[(180)>>2] = $or300$i$i;
-         HEAP32[$arrayidx287$i$i>>2] = $add$ptr17$i$i;
-         $parent301$i$i = ((($add$ptr17$i$i)) + 24|0);
-         HEAP32[$parent301$i$i>>2] = $arrayidx287$i$i;
-         $bk302$i$i = ((($add$ptr17$i$i)) + 12|0);
-         HEAP32[$bk302$i$i>>2] = $add$ptr17$i$i;
-         $fd303$i$i = ((($add$ptr17$i$i)) + 8|0);
-         HEAP32[$fd303$i$i>>2] = $add$ptr17$i$i;
-         break;
-        }
-        $178 = HEAP32[$arrayidx287$i$i>>2]|0;
-        $cmp306$i$i = ($I252$0$i$i|0)==(31);
-        $shr310$i$i = $I252$0$i$i >>> 1;
-        $sub313$i$i = (25 - ($shr310$i$i))|0;
-        $cond315$i$i = $cmp306$i$i ? 0 : $sub313$i$i;
-        $shl316$i$i = $qsize$0$i$i << $cond315$i$i;
-        $K305$0$i$i = $shl316$i$i;$T$0$i$58$i = $178;
-        while(1) {
-         $head317$i$i = ((($T$0$i$58$i)) + 4|0);
-         $179 = HEAP32[$head317$i$i>>2]|0;
-         $and318$i$i = $179 & -8;
-         $cmp319$i$i = ($and318$i$i|0)==($qsize$0$i$i|0);
-         if ($cmp319$i$i) {
-          $T$0$i$58$i$lcssa = $T$0$i$58$i;
-          label = 281;
-          break;
-         }
-         $shr322$i$i = $K305$0$i$i >>> 31;
-         $arrayidx325$i$i = (((($T$0$i$58$i)) + 16|0) + ($shr322$i$i<<2)|0);
-         $shl326$i$i = $K305$0$i$i << 1;
-         $180 = HEAP32[$arrayidx325$i$i>>2]|0;
-         $cmp327$i$i = ($180|0)==(0|0);
-         if ($cmp327$i$i) {
-          $T$0$i$58$i$lcssa283 = $T$0$i$58$i;$arrayidx325$i$i$lcssa = $arrayidx325$i$i;
-          label = 278;
-          break;
-         } else {
-          $K305$0$i$i = $shl326$i$i;$T$0$i$58$i = $180;
-         }
-        }
-        if ((label|0) == 278) {
-         $181 = HEAP32[(192)>>2]|0;
-         $cmp332$i$i = ($arrayidx325$i$i$lcssa>>>0)<($181>>>0);
-         if ($cmp332$i$i) {
-          _abort();
-          // unreachable;
-         } else {
-          HEAP32[$arrayidx325$i$i$lcssa>>2] = $add$ptr17$i$i;
-          $parent337$i$i = ((($add$ptr17$i$i)) + 24|0);
-          HEAP32[$parent337$i$i>>2] = $T$0$i$58$i$lcssa283;
-          $bk338$i$i = ((($add$ptr17$i$i)) + 12|0);
-          HEAP32[$bk338$i$i>>2] = $add$ptr17$i$i;
-          $fd339$i$i = ((($add$ptr17$i$i)) + 8|0);
-          HEAP32[$fd339$i$i>>2] = $add$ptr17$i$i;
-          break;
-         }
-        }
-        else if ((label|0) == 281) {
-         $fd344$i$i = ((($T$0$i$58$i$lcssa)) + 8|0);
-         $182 = HEAP32[$fd344$i$i>>2]|0;
-         $183 = HEAP32[(192)>>2]|0;
-         $cmp350$i$i = ($182>>>0)>=($183>>>0);
-         $not$cmp346$i$i = ($T$0$i$58$i$lcssa>>>0)>=($183>>>0);
-         $184 = $cmp350$i$i & $not$cmp346$i$i;
-         if ($184) {
-          $bk357$i$i = ((($182)) + 12|0);
-          HEAP32[$bk357$i$i>>2] = $add$ptr17$i$i;
-          HEAP32[$fd344$i$i>>2] = $add$ptr17$i$i;
-          $fd359$i$i = ((($add$ptr17$i$i)) + 8|0);
-          HEAP32[$fd359$i$i>>2] = $182;
-          $bk360$i$i = ((($add$ptr17$i$i)) + 12|0);
-          HEAP32[$bk360$i$i>>2] = $T$0$i$58$i$lcssa;
-          $parent361$i$i = ((($add$ptr17$i$i)) + 24|0);
-          HEAP32[$parent361$i$i>>2] = 0;
-          break;
-         } else {
-          _abort();
-          // unreachable;
-         }
-        }
-       }
-      } while(0);
-      $add$ptr369$i$i = ((($add$ptr4$i$37$i)) + 8|0);
-      $retval$0 = $add$ptr369$i$i;
-      return ($retval$0|0);
-     } else {
-      $sp$0$i$i$i = (624);
-     }
-    }
-    while(1) {
-     $185 = HEAP32[$sp$0$i$i$i>>2]|0;
-     $cmp$i$i$i = ($185>>>0)>($119>>>0);
-     if (!($cmp$i$i$i)) {
-      $size$i$i$i = ((($sp$0$i$i$i)) + 4|0);
-      $186 = HEAP32[$size$i$i$i>>2]|0;
-      $add$ptr$i$i$i = (($185) + ($186)|0);
-      $cmp2$i$i$i = ($add$ptr$i$i$i>>>0)>($119>>>0);
-      if ($cmp2$i$i$i) {
-       $add$ptr$i$i$i$lcssa = $add$ptr$i$i$i;
-       break;
-      }
-     }
-     $next$i$i$i = ((($sp$0$i$i$i)) + 8|0);
-     $187 = HEAP32[$next$i$i$i>>2]|0;
-     $sp$0$i$i$i = $187;
-    }
-    $add$ptr2$i$i = ((($add$ptr$i$i$i$lcssa)) + -47|0);
-    $add$ptr3$i$i = ((($add$ptr2$i$i)) + 8|0);
-    $188 = $add$ptr3$i$i;
-    $and$i$14$i = $188 & 7;
-    $cmp$i$15$i = ($and$i$14$i|0)==(0);
-    $189 = (0 - ($188))|0;
-    $and6$i$i = $189 & 7;
-    $cond$i$16$i = $cmp$i$15$i ? 0 : $and6$i$i;
-    $add$ptr7$i$i = (($add$ptr2$i$i) + ($cond$i$16$i)|0);
-    $add$ptr8$i122$i = ((($119)) + 16|0);
-    $cmp9$i$i = ($add$ptr7$i$i>>>0)<($add$ptr8$i122$i>>>0);
-    $cond13$i$i = $cmp9$i$i ? $119 : $add$ptr7$i$i;
-    $add$ptr14$i$i = ((($cond13$i$i)) + 8|0);
-    $add$ptr15$i$i = ((($cond13$i$i)) + 24|0);
-    $sub16$i$i = (($tsize$795$i) + -40)|0;
-    $add$ptr$i$1$i$i = ((($tbase$796$i)) + 8|0);
-    $190 = $add$ptr$i$1$i$i;
-    $and$i$i$i = $190 & 7;
-    $cmp$i$2$i$i = ($and$i$i$i|0)==(0);
-    $191 = (0 - ($190))|0;
-    $and3$i$i$i = $191 & 7;
-    $cond$i$i$i = $cmp$i$2$i$i ? 0 : $and3$i$i$i;
-    $add$ptr4$i$i$i = (($tbase$796$i) + ($cond$i$i$i)|0);
-    $sub5$i$i$i = (($sub16$i$i) - ($cond$i$i$i))|0;
-    HEAP32[(200)>>2] = $add$ptr4$i$i$i;
-    HEAP32[(188)>>2] = $sub5$i$i$i;
-    $or$i$i$i = $sub5$i$i$i | 1;
-    $head$i$i$i = ((($add$ptr4$i$i$i)) + 4|0);
-    HEAP32[$head$i$i$i>>2] = $or$i$i$i;
-    $add$ptr6$i$i$i = (($add$ptr4$i$i$i) + ($sub5$i$i$i)|0);
-    $head7$i$i$i = ((($add$ptr6$i$i$i)) + 4|0);
-    HEAP32[$head7$i$i$i>>2] = 40;
-    $192 = HEAP32[(664)>>2]|0;
-    HEAP32[(204)>>2] = $192;
-    $head$i$17$i = ((($cond13$i$i)) + 4|0);
-    HEAP32[$head$i$17$i>>2] = 27;
-    ;HEAP32[$add$ptr14$i$i>>2]=HEAP32[(624)>>2]|0;HEAP32[$add$ptr14$i$i+4>>2]=HEAP32[(624)+4>>2]|0;HEAP32[$add$ptr14$i$i+8>>2]=HEAP32[(624)+8>>2]|0;HEAP32[$add$ptr14$i$i+12>>2]=HEAP32[(624)+12>>2]|0;
-    HEAP32[(624)>>2] = $tbase$796$i;
-    HEAP32[(628)>>2] = $tsize$795$i;
-    HEAP32[(636)>>2] = 0;
-    HEAP32[(632)>>2] = $add$ptr14$i$i;
-    $p$0$i$i = $add$ptr15$i$i;
-    while(1) {
-     $add$ptr24$i$i = ((($p$0$i$i)) + 4|0);
-     HEAP32[$add$ptr24$i$i>>2] = 7;
-     $193 = ((($add$ptr24$i$i)) + 4|0);
-     $cmp27$i$i = ($193>>>0)<($add$ptr$i$i$i$lcssa>>>0);
-     if ($cmp27$i$i) {
-      $p$0$i$i = $add$ptr24$i$i;
-     } else {
-      break;
-     }
-    }
-    $cmp28$i$i = ($cond13$i$i|0)==($119|0);
-    if (!($cmp28$i$i)) {
-     $sub$ptr$lhs$cast$i$i = $cond13$i$i;
-     $sub$ptr$rhs$cast$i$i = $119;
-     $sub$ptr$sub$i$i = (($sub$ptr$lhs$cast$i$i) - ($sub$ptr$rhs$cast$i$i))|0;
-     $194 = HEAP32[$head$i$17$i>>2]|0;
-     $and32$i$i = $194 & -2;
-     HEAP32[$head$i$17$i>>2] = $and32$i$i;
-     $or33$i$i = $sub$ptr$sub$i$i | 1;
-     $head34$i$i = ((($119)) + 4|0);
-     HEAP32[$head34$i$i>>2] = $or33$i$i;
-     HEAP32[$cond13$i$i>>2] = $sub$ptr$sub$i$i;
-     $shr$i$i = $sub$ptr$sub$i$i >>> 3;
-     $cmp36$i$i = ($sub$ptr$sub$i$i>>>0)<(256);
-     if ($cmp36$i$i) {
-      $shl$i$19$i = $shr$i$i << 1;
-      $arrayidx$i$20$i = (216 + ($shl$i$19$i<<2)|0);
-      $195 = HEAP32[44]|0;
-      $shl39$i$i = 1 << $shr$i$i;
-      $and40$i$i = $195 & $shl39$i$i;
-      $tobool$i$i = ($and40$i$i|0)==(0);
-      if ($tobool$i$i) {
-       $or44$i$i = $195 | $shl39$i$i;
-       HEAP32[44] = $or44$i$i;
-       $$pre$i$i = ((($arrayidx$i$20$i)) + 8|0);
-       $$pre$phi$i$iZ2D = $$pre$i$i;$F$0$i$i = $arrayidx$i$20$i;
-      } else {
-       $196 = ((($arrayidx$i$20$i)) + 8|0);
-       $197 = HEAP32[$196>>2]|0;
-       $198 = HEAP32[(192)>>2]|0;
-       $cmp46$i$i = ($197>>>0)<($198>>>0);
-       if ($cmp46$i$i) {
-        _abort();
-        // unreachable;
-       } else {
-        $$pre$phi$i$iZ2D = $196;$F$0$i$i = $197;
-       }
-      }
-      HEAP32[$$pre$phi$i$iZ2D>>2] = $119;
-      $bk$i$i = ((($F$0$i$i)) + 12|0);
-      HEAP32[$bk$i$i>>2] = $119;
-      $fd54$i$i = ((($119)) + 8|0);
-      HEAP32[$fd54$i$i>>2] = $F$0$i$i;
-      $bk55$i$i = ((($119)) + 12|0);
-      HEAP32[$bk55$i$i>>2] = $arrayidx$i$20$i;
-      break;
-     }
-     $shr58$i$i = $sub$ptr$sub$i$i >>> 8;
-     $cmp59$i$i = ($shr58$i$i|0)==(0);
-     if ($cmp59$i$i) {
-      $I57$0$i$i = 0;
-     } else {
-      $cmp63$i$i = ($sub$ptr$sub$i$i>>>0)>(16777215);
-      if ($cmp63$i$i) {
-       $I57$0$i$i = 31;
-      } else {
-       $sub67$i$i = (($shr58$i$i) + 1048320)|0;
-       $shr68$i$i = $sub67$i$i >>> 16;
-       $and69$i$i = $shr68$i$i & 8;
-       $shl70$i$i = $shr58$i$i << $and69$i$i;
-       $sub71$i$i = (($shl70$i$i) + 520192)|0;
-       $shr72$i$i = $sub71$i$i >>> 16;
-       $and73$i$i = $shr72$i$i & 4;
-       $add74$i$i = $and73$i$i | $and69$i$i;
-       $shl75$i$i = $shl70$i$i << $and73$i$i;
-       $sub76$i$i = (($shl75$i$i) + 245760)|0;
-       $shr77$i$i = $sub76$i$i >>> 16;
-       $and78$i$i = $shr77$i$i & 2;
-       $add79$i$i = $add74$i$i | $and78$i$i;
-       $sub80$i$i = (14 - ($add79$i$i))|0;
-       $shl81$i$i = $shl75$i$i << $and78$i$i;
-       $shr82$i$i = $shl81$i$i >>> 15;
-       $add83$i$i = (($sub80$i$i) + ($shr82$i$i))|0;
-       $shl84$i$i = $add83$i$i << 1;
-       $add85$i$i = (($add83$i$i) + 7)|0;
-       $shr86$i$i = $sub$ptr$sub$i$i >>> $add85$i$i;
-       $and87$i$i = $shr86$i$i & 1;
-       $add88$i$i = $and87$i$i | $shl84$i$i;
-       $I57$0$i$i = $add88$i$i;
-      }
-     }
-     $arrayidx91$i$i = (480 + ($I57$0$i$i<<2)|0);
-     $index$i$i = ((($119)) + 28|0);
-     HEAP32[$index$i$i>>2] = $I57$0$i$i;
-     $arrayidx92$i$i = ((($119)) + 20|0);
-     HEAP32[$arrayidx92$i$i>>2] = 0;
-     HEAP32[$add$ptr8$i122$i>>2] = 0;
-     $199 = HEAP32[(180)>>2]|0;
-     $shl95$i$i = 1 << $I57$0$i$i;
-     $and96$i$i = $199 & $shl95$i$i;
-     $tobool97$i$i = ($and96$i$i|0)==(0);
-     if ($tobool97$i$i) {
-      $or101$i$i = $199 | $shl95$i$i;
-      HEAP32[(180)>>2] = $or101$i$i;
-      HEAP32[$arrayidx91$i$i>>2] = $119;
-      $parent$i$i = ((($119)) + 24|0);
-      HEAP32[$parent$i$i>>2] = $arrayidx91$i$i;
-      $bk102$i$i = ((($119)) + 12|0);
-      HEAP32[$bk102$i$i>>2] = $119;
-      $fd103$i$i = ((($119)) + 8|0);
-      HEAP32[$fd103$i$i>>2] = $119;
-      break;
-     }
-     $200 = HEAP32[$arrayidx91$i$i>>2]|0;
-     $cmp106$i$i = ($I57$0$i$i|0)==(31);
-     $shr110$i$i = $I57$0$i$i >>> 1;
-     $sub113$i$i = (25 - ($shr110$i$i))|0;
-     $cond115$i$i = $cmp106$i$i ? 0 : $sub113$i$i;
-     $shl116$i$i = $sub$ptr$sub$i$i << $cond115$i$i;
-     $K105$0$i$i = $shl116$i$i;$T$0$i$i = $200;
-     while(1) {
-      $head118$i$i = ((($T$0$i$i)) + 4|0);
-      $201 = HEAP32[$head118$i$i>>2]|0;
-      $and119$i$i = $201 & -8;
-      $cmp120$i$i = ($and119$i$i|0)==($sub$ptr$sub$i$i|0);
-      if ($cmp120$i$i) {
-       $T$0$i$i$lcssa = $T$0$i$i;
-       label = 307;
-       break;
-      }
-      $shr123$i$i = $K105$0$i$i >>> 31;
-      $arrayidx126$i$i = (((($T$0$i$i)) + 16|0) + ($shr123$i$i<<2)|0);
-      $shl127$i$i = $K105$0$i$i << 1;
-      $202 = HEAP32[$arrayidx126$i$i>>2]|0;
-      $cmp128$i$i = ($202|0)==(0|0);
-      if ($cmp128$i$i) {
-       $T$0$i$i$lcssa284 = $T$0$i$i;$arrayidx126$i$i$lcssa = $arrayidx126$i$i;
-       label = 304;
-       break;
-      } else {
-       $K105$0$i$i = $shl127$i$i;$T$0$i$i = $202;
-      }
-     }
-     if ((label|0) == 304) {
-      $203 = HEAP32[(192)>>2]|0;
-      $cmp133$i$i = ($arrayidx126$i$i$lcssa>>>0)<($203>>>0);
-      if ($cmp133$i$i) {
-       _abort();
-       // unreachable;
-      } else {
-       HEAP32[$arrayidx126$i$i$lcssa>>2] = $119;
-       $parent138$i$i = ((($119)) + 24|0);
-       HEAP32[$parent138$i$i>>2] = $T$0$i$i$lcssa284;
-       $bk139$i$i = ((($119)) + 12|0);
-       HEAP32[$bk139$i$i>>2] = $119;
-       $fd140$i$i = ((($119)) + 8|0);
-       HEAP32[$fd140$i$i>>2] = $119;
-       break;
-      }
-     }
-     else if ((label|0) == 307) {
-      $fd148$i$i = ((($T$0$i$i$lcssa)) + 8|0);
-      $204 = HEAP32[$fd148$i$i>>2]|0;
-      $205 = HEAP32[(192)>>2]|0;
-      $cmp153$i$i = ($204>>>0)>=($205>>>0);
-      $not$cmp150$i$i = ($T$0$i$i$lcssa>>>0)>=($205>>>0);
-      $206 = $cmp153$i$i & $not$cmp150$i$i;
-      if ($206) {
-       $bk158$i$i = ((($204)) + 12|0);
-       HEAP32[$bk158$i$i>>2] = $119;
-       HEAP32[$fd148$i$i>>2] = $119;
-       $fd160$i$i = ((($119)) + 8|0);
-       HEAP32[$fd160$i$i>>2] = $204;
-       $bk161$i$i = ((($119)) + 12|0);
-       HEAP32[$bk161$i$i>>2] = $T$0$i$i$lcssa;
-       $parent162$i$i = ((($119)) + 24|0);
-       HEAP32[$parent162$i$i>>2] = 0;
-       break;
-      } else {
-       _abort();
-       // unreachable;
-      }
-     }
-    }
-   }
-  } while(0);
-  $207 = HEAP32[(188)>>2]|0;
-  $cmp257$i = ($207>>>0)>($nb$0>>>0);
-  if ($cmp257$i) {
-   $sub260$i = (($207) - ($nb$0))|0;
-   HEAP32[(188)>>2] = $sub260$i;
-   $208 = HEAP32[(200)>>2]|0;
-   $add$ptr262$i = (($208) + ($nb$0)|0);
-   HEAP32[(200)>>2] = $add$ptr262$i;
-   $or264$i = $sub260$i | 1;
-   $head265$i = ((($add$ptr262$i)) + 4|0);
-   HEAP32[$head265$i>>2] = $or264$i;
-   $or267$i = $nb$0 | 3;
-   $head268$i = ((($208)) + 4|0);
-   HEAP32[$head268$i>>2] = $or267$i;
-   $add$ptr269$i = ((($208)) + 8|0);
-   $retval$0 = $add$ptr269$i;
-   return ($retval$0|0);
-  }
- }
- $call275$i = (___errno_location()|0);
- HEAP32[$call275$i>>2] = 12;
- $retval$0 = 0;
- return ($retval$0|0);
-}
-function _free($mem) {
- $mem = $mem|0;
- var $$pre = 0, $$pre$phiZ2D = 0, $$pre312 = 0, $$pre313 = 0, $0 = 0, $1 = 0, $10 = 0, $11 = 0, $12 = 0, $13 = 0, $14 = 0, $15 = 0, $16 = 0, $17 = 0, $18 = 0, $19 = 0, $2 = 0, $20 = 0, $21 = 0, $22 = 0;
- var $23 = 0, $24 = 0, $25 = 0, $26 = 0, $27 = 0, $28 = 0, $29 = 0, $3 = 0, $30 = 0, $31 = 0, $32 = 0, $33 = 0, $34 = 0, $35 = 0, $36 = 0, $37 = 0, $38 = 0, $39 = 0, $4 = 0, $40 = 0;
- var $41 = 0, $42 = 0, $43 = 0, $44 = 0, $45 = 0, $46 = 0, $47 = 0, $48 = 0, $49 = 0, $5 = 0, $50 = 0, $51 = 0, $52 = 0, $53 = 0, $54 = 0, $55 = 0, $56 = 0, $57 = 0, $58 = 0, $59 = 0;
- var $6 = 0, $60 = 0, $61 = 0, $62 = 0, $63 = 0, $64 = 0, $65 = 0, $66 = 0, $67 = 0, $68 = 0, $69 = 0, $7 = 0, $70 = 0, $71 = 0, $72 = 0, $73 = 0, $74 = 0, $8 = 0, $9 = 0, $F510$0 = 0;
- var $I534$0 = 0, $K583$0 = 0, $R$1 = 0, $R$1$lcssa = 0, $R$3 = 0, $R332$1 = 0, $R332$1$lcssa = 0, $R332$3 = 0, $RP$1 = 0, $RP$1$lcssa = 0, $RP360$1 = 0, $RP360$1$lcssa = 0, $T$0 = 0, $T$0$lcssa = 0, $T$0$lcssa319 = 0, $add$ptr = 0, $add$ptr16 = 0, $add$ptr217 = 0, $add$ptr261 = 0, $add$ptr482 = 0;
- var $add$ptr498 = 0, $add$ptr6 = 0, $add17 = 0, $add246 = 0, $add258 = 0, $add267 = 0, $add550 = 0, $add555 = 0, $add559 = 0, $add561 = 0, $add564 = 0, $and = 0, $and140 = 0, $and210 = 0, $and215 = 0, $and232 = 0, $and240 = 0, $and266 = 0, $and301 = 0, $and410 = 0;
- var $and46 = 0, $and495 = 0, $and5 = 0, $and512 = 0, $and545 = 0, $and549 = 0, $and554 = 0, $and563 = 0, $and574 = 0, $and592 = 0, $and8 = 0, $arrayidx = 0, $arrayidx108 = 0, $arrayidx113 = 0, $arrayidx130 = 0, $arrayidx149 = 0, $arrayidx157 = 0, $arrayidx182 = 0, $arrayidx188 = 0, $arrayidx198 = 0;
- var $arrayidx279 = 0, $arrayidx362 = 0, $arrayidx374 = 0, $arrayidx379 = 0, $arrayidx400 = 0, $arrayidx419 = 0, $arrayidx427 = 0, $arrayidx454 = 0, $arrayidx460 = 0, $arrayidx470 = 0, $arrayidx509 = 0, $arrayidx567 = 0, $arrayidx570 = 0, $arrayidx599 = 0, $arrayidx599$lcssa = 0, $arrayidx99 = 0, $bk = 0, $bk275 = 0, $bk286 = 0, $bk321 = 0;
- var $bk333 = 0, $bk34 = 0, $bk343 = 0, $bk529 = 0, $bk531 = 0, $bk580 = 0, $bk611 = 0, $bk631 = 0, $bk634 = 0, $bk66 = 0, $bk73 = 0, $bk82 = 0, $child = 0, $child171 = 0, $child361 = 0, $child443 = 0, $child569 = 0, $cmp = 0, $cmp$i = 0, $cmp1 = 0;
- var $cmp100 = 0, $cmp104 = 0, $cmp109 = 0, $cmp114 = 0, $cmp118 = 0, $cmp127 = 0, $cmp13 = 0, $cmp131 = 0, $cmp143 = 0, $cmp150 = 0, $cmp162 = 0, $cmp165 = 0, $cmp173 = 0, $cmp176 = 0, $cmp18 = 0, $cmp189 = 0, $cmp192 = 0, $cmp2 = 0, $cmp211 = 0, $cmp22 = 0;
- var $cmp228 = 0, $cmp243 = 0, $cmp249 = 0, $cmp25 = 0, $cmp255 = 0, $cmp269 = 0, $cmp280 = 0, $cmp283 = 0, $cmp287 = 0, $cmp29 = 0, $cmp296 = 0, $cmp305 = 0, $cmp308 = 0, $cmp31 = 0, $cmp312 = 0, $cmp334 = 0, $cmp340 = 0, $cmp344 = 0, $cmp348 = 0, $cmp35 = 0;
- var $cmp363 = 0, $cmp368 = 0, $cmp375 = 0, $cmp380 = 0, $cmp386 = 0, $cmp395 = 0, $cmp401 = 0, $cmp413 = 0, $cmp42 = 0, $cmp420 = 0, $cmp432 = 0, $cmp435 = 0, $cmp445 = 0, $cmp448 = 0, $cmp461 = 0, $cmp464 = 0, $cmp484 = 0, $cmp50 = 0, $cmp502 = 0, $cmp519 = 0;
- var $cmp53 = 0, $cmp536 = 0, $cmp540 = 0, $cmp57 = 0, $cmp584 = 0, $cmp593 = 0, $cmp601 = 0, $cmp605 = 0, $cmp624 = 0, $cmp640 = 0, $cmp74 = 0, $cmp80 = 0, $cmp83 = 0, $cmp87 = 0, $cond = 0, $cond291 = 0, $cond292 = 0, $dec = 0, $fd = 0, $fd273 = 0;
- var $fd311 = 0, $fd322$pre$phiZ2D = 0, $fd338 = 0, $fd347 = 0, $fd530 = 0, $fd56 = 0, $fd581 = 0, $fd612 = 0, $fd620 = 0, $fd633 = 0, $fd67$pre$phiZ2D = 0, $fd78 = 0, $fd86 = 0, $head = 0, $head209 = 0, $head216 = 0, $head231 = 0, $head248 = 0, $head260 = 0, $head481 = 0;
- var $head497 = 0, $head591 = 0, $idx$neg = 0, $index = 0, $index399 = 0, $index568 = 0, $neg = 0, $neg139 = 0, $neg300 = 0, $neg409 = 0, $next4$i = 0, $not$cmp621 = 0, $or = 0, $or247 = 0, $or259 = 0, $or480 = 0, $or496 = 0, $or516 = 0, $or578 = 0, $p$1 = 0;
- var $parent = 0, $parent170 = 0, $parent183 = 0, $parent199 = 0, $parent331 = 0, $parent442 = 0, $parent455 = 0, $parent471 = 0, $parent579 = 0, $parent610 = 0, $parent635 = 0, $psize$1 = 0, $psize$2 = 0, $shl = 0, $shl138 = 0, $shl278 = 0, $shl299 = 0, $shl408 = 0, $shl45 = 0, $shl508 = 0;
- var $shl511 = 0, $shl546 = 0, $shl551 = 0, $shl557 = 0, $shl560 = 0, $shl573 = 0, $shl590 = 0, $shl600 = 0, $shr = 0, $shr268 = 0, $shr501 = 0, $shr535 = 0, $shr544 = 0, $shr548 = 0, $shr553 = 0, $shr558 = 0, $shr562 = 0, $shr586 = 0, $shr596 = 0, $sp$0$i = 0;
- var $sp$0$in$i = 0, $sub = 0, $sub547 = 0, $sub552 = 0, $sub556 = 0, $sub589 = 0, $tobool233 = 0, $tobool241 = 0, $tobool513 = 0, $tobool575 = 0, $tobool9 = 0, label = 0, sp = 0;
- sp = STACKTOP;
- $cmp = ($mem|0)==(0|0);
- if ($cmp) {
-  return;
- }
- $add$ptr = ((($mem)) + -8|0);
- $0 = HEAP32[(192)>>2]|0;
- $cmp1 = ($add$ptr>>>0)<($0>>>0);
- if ($cmp1) {
-  _abort();
-  // unreachable;
- }
- $head = ((($mem)) + -4|0);
- $1 = HEAP32[$head>>2]|0;
- $and = $1 & 3;
- $cmp2 = ($and|0)==(1);
- if ($cmp2) {
-  _abort();
-  // unreachable;
- }
- $and5 = $1 & -8;
- $add$ptr6 = (($add$ptr) + ($and5)|0);
- $and8 = $1 & 1;
- $tobool9 = ($and8|0)==(0);
- do {
-  if ($tobool9) {
-   $2 = HEAP32[$add$ptr>>2]|0;
-   $cmp13 = ($and|0)==(0);
-   if ($cmp13) {
-    return;
-   }
-   $idx$neg = (0 - ($2))|0;
-   $add$ptr16 = (($add$ptr) + ($idx$neg)|0);
-   $add17 = (($2) + ($and5))|0;
-   $cmp18 = ($add$ptr16>>>0)<($0>>>0);
-   if ($cmp18) {
-    _abort();
-    // unreachable;
-   }
-   $3 = HEAP32[(196)>>2]|0;
-   $cmp22 = ($add$ptr16|0)==($3|0);
-   if ($cmp22) {
-    $head209 = ((($add$ptr6)) + 4|0);
-    $27 = HEAP32[$head209>>2]|0;
-    $and210 = $27 & 3;
-    $cmp211 = ($and210|0)==(3);
-    if (!($cmp211)) {
-     $p$1 = $add$ptr16;$psize$1 = $add17;
-     break;
-    }
-    HEAP32[(184)>>2] = $add17;
-    $and215 = $27 & -2;
-    HEAP32[$head209>>2] = $and215;
-    $or = $add17 | 1;
-    $head216 = ((($add$ptr16)) + 4|0);
-    HEAP32[$head216>>2] = $or;
-    $add$ptr217 = (($add$ptr16) + ($add17)|0);
-    HEAP32[$add$ptr217>>2] = $add17;
-    return;
-   }
-   $shr = $2 >>> 3;
-   $cmp25 = ($2>>>0)<(256);
-   if ($cmp25) {
-    $fd = ((($add$ptr16)) + 8|0);
-    $4 = HEAP32[$fd>>2]|0;
-    $bk = ((($add$ptr16)) + 12|0);
-    $5 = HEAP32[$bk>>2]|0;
-    $shl = $shr << 1;
-    $arrayidx = (216 + ($shl<<2)|0);
-    $cmp29 = ($4|0)==($arrayidx|0);
-    if (!($cmp29)) {
-     $cmp31 = ($4>>>0)<($0>>>0);
-     if ($cmp31) {
-      _abort();
-      // unreachable;
-     }
-     $bk34 = ((($4)) + 12|0);
-     $6 = HEAP32[$bk34>>2]|0;
-     $cmp35 = ($6|0)==($add$ptr16|0);
-     if (!($cmp35)) {
-      _abort();
-      // unreachable;
-     }
-    }
-    $cmp42 = ($5|0)==($4|0);
-    if ($cmp42) {
-     $shl45 = 1 << $shr;
-     $neg = $shl45 ^ -1;
-     $7 = HEAP32[44]|0;
-     $and46 = $7 & $neg;
-     HEAP32[44] = $and46;
-     $p$1 = $add$ptr16;$psize$1 = $add17;
-     break;
-    }
-    $cmp50 = ($5|0)==($arrayidx|0);
-    if ($cmp50) {
-     $$pre313 = ((($5)) + 8|0);
-     $fd67$pre$phiZ2D = $$pre313;
-    } else {
-     $cmp53 = ($5>>>0)<($0>>>0);
-     if ($cmp53) {
-      _abort();
-      // unreachable;
-     }
-     $fd56 = ((($5)) + 8|0);
-     $8 = HEAP32[$fd56>>2]|0;
-     $cmp57 = ($8|0)==($add$ptr16|0);
-     if ($cmp57) {
-      $fd67$pre$phiZ2D = $fd56;
-     } else {
-      _abort();
-      // unreachable;
-     }
-    }
-    $bk66 = ((($4)) + 12|0);
-    HEAP32[$bk66>>2] = $5;
-    HEAP32[$fd67$pre$phiZ2D>>2] = $4;
-    $p$1 = $add$ptr16;$psize$1 = $add17;
-    break;
-   }
-   $parent = ((($add$ptr16)) + 24|0);
-   $9 = HEAP32[$parent>>2]|0;
-   $bk73 = ((($add$ptr16)) + 12|0);
-   $10 = HEAP32[$bk73>>2]|0;
-   $cmp74 = ($10|0)==($add$ptr16|0);
-   do {
-    if ($cmp74) {
-     $child = ((($add$ptr16)) + 16|0);
-     $arrayidx99 = ((($child)) + 4|0);
-     $14 = HEAP32[$arrayidx99>>2]|0;
-     $cmp100 = ($14|0)==(0|0);
-     if ($cmp100) {
-      $15 = HEAP32[$child>>2]|0;
-      $cmp104 = ($15|0)==(0|0);
-      if ($cmp104) {
-       $R$3 = 0;
-       break;
-      } else {
-       $R$1 = $15;$RP$1 = $child;
-      }
-     } else {
-      $R$1 = $14;$RP$1 = $arrayidx99;
-     }
-     while(1) {
-      $arrayidx108 = ((($R$1)) + 20|0);
-      $16 = HEAP32[$arrayidx108>>2]|0;
-      $cmp109 = ($16|0)==(0|0);
-      if (!($cmp109)) {
-       $R$1 = $16;$RP$1 = $arrayidx108;
-       continue;
-      }
-      $arrayidx113 = ((($R$1)) + 16|0);
-      $17 = HEAP32[$arrayidx113>>2]|0;
-      $cmp114 = ($17|0)==(0|0);
-      if ($cmp114) {
-       $R$1$lcssa = $R$1;$RP$1$lcssa = $RP$1;
-       break;
-      } else {
-       $R$1 = $17;$RP$1 = $arrayidx113;
-      }
-     }
-     $cmp118 = ($RP$1$lcssa>>>0)<($0>>>0);
-     if ($cmp118) {
-      _abort();
-      // unreachable;
-     } else {
-      HEAP32[$RP$1$lcssa>>2] = 0;
-      $R$3 = $R$1$lcssa;
-      break;
-     }
-    } else {
-     $fd78 = ((($add$ptr16)) + 8|0);
-     $11 = HEAP32[$fd78>>2]|0;
-     $cmp80 = ($11>>>0)<($0>>>0);
-     if ($cmp80) {
-      _abort();
-      // unreachable;
-     }
-     $bk82 = ((($11)) + 12|0);
-     $12 = HEAP32[$bk82>>2]|0;
-     $cmp83 = ($12|0)==($add$ptr16|0);
-     if (!($cmp83)) {
-      _abort();
-      // unreachable;
-     }
-     $fd86 = ((($10)) + 8|0);
-     $13 = HEAP32[$fd86>>2]|0;
-     $cmp87 = ($13|0)==($add$ptr16|0);
-     if ($cmp87) {
-      HEAP32[$bk82>>2] = $10;
-      HEAP32[$fd86>>2] = $11;
-      $R$3 = $10;
-      break;
-     } else {
-      _abort();
-      // unreachable;
-     }
-    }
-   } while(0);
-   $cmp127 = ($9|0)==(0|0);
-   if ($cmp127) {
-    $p$1 = $add$ptr16;$psize$1 = $add17;
-   } else {
-    $index = ((($add$ptr16)) + 28|0);
-    $18 = HEAP32[$index>>2]|0;
-    $arrayidx130 = (480 + ($18<<2)|0);
-    $19 = HEAP32[$arrayidx130>>2]|0;
-    $cmp131 = ($add$ptr16|0)==($19|0);
-    if ($cmp131) {
-     HEAP32[$arrayidx130>>2] = $R$3;
-     $cond291 = ($R$3|0)==(0|0);
-     if ($cond291) {
-      $shl138 = 1 << $18;
-      $neg139 = $shl138 ^ -1;
-      $20 = HEAP32[(180)>>2]|0;
-      $and140 = $20 & $neg139;
-      HEAP32[(180)>>2] = $and140;
-      $p$1 = $add$ptr16;$psize$1 = $add17;
-      break;
-     }
-    } else {
-     $21 = HEAP32[(192)>>2]|0;
-     $cmp143 = ($9>>>0)<($21>>>0);
-     if ($cmp143) {
-      _abort();
-      // unreachable;
-     }
-     $arrayidx149 = ((($9)) + 16|0);
-     $22 = HEAP32[$arrayidx149>>2]|0;
-     $cmp150 = ($22|0)==($add$ptr16|0);
-     if ($cmp150) {
-      HEAP32[$arrayidx149>>2] = $R$3;
-     } else {
-      $arrayidx157 = ((($9)) + 20|0);
-      HEAP32[$arrayidx157>>2] = $R$3;
-     }
-     $cmp162 = ($R$3|0)==(0|0);
-     if ($cmp162) {
-      $p$1 = $add$ptr16;$psize$1 = $add17;
-      break;
-     }
-    }
-    $23 = HEAP32[(192)>>2]|0;
-    $cmp165 = ($R$3>>>0)<($23>>>0);
-    if ($cmp165) {
-     _abort();
-     // unreachable;
-    }
-    $parent170 = ((($R$3)) + 24|0);
-    HEAP32[$parent170>>2] = $9;
-    $child171 = ((($add$ptr16)) + 16|0);
-    $24 = HEAP32[$child171>>2]|0;
-    $cmp173 = ($24|0)==(0|0);
-    do {
-     if (!($cmp173)) {
-      $cmp176 = ($24>>>0)<($23>>>0);
-      if ($cmp176) {
-       _abort();
-       // unreachable;
-      } else {
-       $arrayidx182 = ((($R$3)) + 16|0);
-       HEAP32[$arrayidx182>>2] = $24;
-       $parent183 = ((($24)) + 24|0);
-       HEAP32[$parent183>>2] = $R$3;
-       break;
-      }
-     }
-    } while(0);
-    $arrayidx188 = ((($child171)) + 4|0);
-    $25 = HEAP32[$arrayidx188>>2]|0;
-    $cmp189 = ($25|0)==(0|0);
-    if ($cmp189) {
-     $p$1 = $add$ptr16;$psize$1 = $add17;
-    } else {
-     $26 = HEAP32[(192)>>2]|0;
-     $cmp192 = ($25>>>0)<($26>>>0);
-     if ($cmp192) {
-      _abort();
-      // unreachable;
-     } else {
-      $arrayidx198 = ((($R$3)) + 20|0);
-      HEAP32[$arrayidx198>>2] = $25;
-      $parent199 = ((($25)) + 24|0);
-      HEAP32[$parent199>>2] = $R$3;
-      $p$1 = $add$ptr16;$psize$1 = $add17;
-      break;
-     }
-    }
-   }
-  } else {
-   $p$1 = $add$ptr;$psize$1 = $and5;
-  }
- } while(0);
- $cmp228 = ($p$1>>>0)<($add$ptr6>>>0);
- if (!($cmp228)) {
-  _abort();
-  // unreachable;
- }
- $head231 = ((($add$ptr6)) + 4|0);
- $28 = HEAP32[$head231>>2]|0;
- $and232 = $28 & 1;
- $tobool233 = ($and232|0)==(0);
- if ($tobool233) {
-  _abort();
-  // unreachable;
- }
- $and240 = $28 & 2;
- $tobool241 = ($and240|0)==(0);
- if ($tobool241) {
-  $29 = HEAP32[(200)>>2]|0;
-  $cmp243 = ($add$ptr6|0)==($29|0);
-  if ($cmp243) {
-   $30 = HEAP32[(188)>>2]|0;
-   $add246 = (($30) + ($psize$1))|0;
-   HEAP32[(188)>>2] = $add246;
-   HEAP32[(200)>>2] = $p$1;
-   $or247 = $add246 | 1;
-   $head248 = ((($p$1)) + 4|0);
-   HEAP32[$head248>>2] = $or247;
-   $31 = HEAP32[(196)>>2]|0;
-   $cmp249 = ($p$1|0)==($31|0);
-   if (!($cmp249)) {
-    return;
-   }
-   HEAP32[(196)>>2] = 0;
-   HEAP32[(184)>>2] = 0;
-   return;
-  }
-  $32 = HEAP32[(196)>>2]|0;
-  $cmp255 = ($add$ptr6|0)==($32|0);
-  if ($cmp255) {
-   $33 = HEAP32[(184)>>2]|0;
-   $add258 = (($33) + ($psize$1))|0;
-   HEAP32[(184)>>2] = $add258;
-   HEAP32[(196)>>2] = $p$1;
-   $or259 = $add258 | 1;
-   $head260 = ((($p$1)) + 4|0);
-   HEAP32[$head260>>2] = $or259;
-   $add$ptr261 = (($p$1) + ($add258)|0);
-   HEAP32[$add$ptr261>>2] = $add258;
-   return;
-  }
-  $and266 = $28 & -8;
-  $add267 = (($and266) + ($psize$1))|0;
-  $shr268 = $28 >>> 3;
-  $cmp269 = ($28>>>0)<(256);
-  do {
-   if ($cmp269) {
-    $fd273 = ((($add$ptr6)) + 8|0);
-    $34 = HEAP32[$fd273>>2]|0;
-    $bk275 = ((($add$ptr6)) + 12|0);
-    $35 = HEAP32[$bk275>>2]|0;
-    $shl278 = $shr268 << 1;
-    $arrayidx279 = (216 + ($shl278<<2)|0);
-    $cmp280 = ($34|0)==($arrayidx279|0);
-    if (!($cmp280)) {
-     $36 = HEAP32[(192)>>2]|0;
-     $cmp283 = ($34>>>0)<($36>>>0);
-     if ($cmp283) {
-      _abort();
-      // unreachable;
-     }
-     $bk286 = ((($34)) + 12|0);
-     $37 = HEAP32[$bk286>>2]|0;
-     $cmp287 = ($37|0)==($add$ptr6|0);
-     if (!($cmp287)) {
-      _abort();
-      // unreachable;
-     }
-    }
-    $cmp296 = ($35|0)==($34|0);
-    if ($cmp296) {
-     $shl299 = 1 << $shr268;
-     $neg300 = $shl299 ^ -1;
-     $38 = HEAP32[44]|0;
-     $and301 = $38 & $neg300;
-     HEAP32[44] = $and301;
-     break;
-    }
-    $cmp305 = ($35|0)==($arrayidx279|0);
-    if ($cmp305) {
-     $$pre312 = ((($35)) + 8|0);
-     $fd322$pre$phiZ2D = $$pre312;
-    } else {
-     $39 = HEAP32[(192)>>2]|0;
-     $cmp308 = ($35>>>0)<($39>>>0);
-     if ($cmp308) {
-      _abort();
-      // unreachable;
-     }
-     $fd311 = ((($35)) + 8|0);
-     $40 = HEAP32[$fd311>>2]|0;
-     $cmp312 = ($40|0)==($add$ptr6|0);
-     if ($cmp312) {
-      $fd322$pre$phiZ2D = $fd311;
-     } else {
-      _abort();
-      // unreachable;
-     }
-    }
-    $bk321 = ((($34)) + 12|0);
-    HEAP32[$bk321>>2] = $35;
-    HEAP32[$fd322$pre$phiZ2D>>2] = $34;
-   } else {
-    $parent331 = ((($add$ptr6)) + 24|0);
-    $41 = HEAP32[$parent331>>2]|0;
-    $bk333 = ((($add$ptr6)) + 12|0);
-    $42 = HEAP32[$bk333>>2]|0;
-    $cmp334 = ($42|0)==($add$ptr6|0);
-    do {
-     if ($cmp334) {
-      $child361 = ((($add$ptr6)) + 16|0);
-      $arrayidx362 = ((($child361)) + 4|0);
-      $47 = HEAP32[$arrayidx362>>2]|0;
-      $cmp363 = ($47|0)==(0|0);
-      if ($cmp363) {
-       $48 = HEAP32[$child361>>2]|0;
-       $cmp368 = ($48|0)==(0|0);
-       if ($cmp368) {
-        $R332$3 = 0;
-        break;
-       } else {
-        $R332$1 = $48;$RP360$1 = $child361;
-       }
-      } else {
-       $R332$1 = $47;$RP360$1 = $arrayidx362;
-      }
-      while(1) {
-       $arrayidx374 = ((($R332$1)) + 20|0);
-       $49 = HEAP32[$arrayidx374>>2]|0;
-       $cmp375 = ($49|0)==(0|0);
-       if (!($cmp375)) {
-        $R332$1 = $49;$RP360$1 = $arrayidx374;
-        continue;
-       }
-       $arrayidx379 = ((($R332$1)) + 16|0);
-       $50 = HEAP32[$arrayidx379>>2]|0;
-       $cmp380 = ($50|0)==(0|0);
-       if ($cmp380) {
-        $R332$1$lcssa = $R332$1;$RP360$1$lcssa = $RP360$1;
-        break;
-       } else {
-        $R332$1 = $50;$RP360$1 = $arrayidx379;
-       }
-      }
-      $51 = HEAP32[(192)>>2]|0;
-      $cmp386 = ($RP360$1$lcssa>>>0)<($51>>>0);
-      if ($cmp386) {
-       _abort();
-       // unreachable;
-      } else {
-       HEAP32[$RP360$1$lcssa>>2] = 0;
-       $R332$3 = $R332$1$lcssa;
-       break;
-      }
-     } else {
-      $fd338 = ((($add$ptr6)) + 8|0);
-      $43 = HEAP32[$fd338>>2]|0;
-      $44 = HEAP32[(192)>>2]|0;
-      $cmp340 = ($43>>>0)<($44>>>0);
-      if ($cmp340) {
-       _abort();
-       // unreachable;
-      }
-      $bk343 = ((($43)) + 12|0);
-      $45 = HEAP32[$bk343>>2]|0;
-      $cmp344 = ($45|0)==($add$ptr6|0);
-      if (!($cmp344)) {
-       _abort();
-       // unreachable;
-      }
-      $fd347 = ((($42)) + 8|0);
-      $46 = HEAP32[$fd347>>2]|0;
-      $cmp348 = ($46|0)==($add$ptr6|0);
-      if ($cmp348) {
-       HEAP32[$bk343>>2] = $42;
-       HEAP32[$fd347>>2] = $43;
-       $R332$3 = $42;
-       break;
-      } else {
-       _abort();
-       // unreachable;
-      }
-     }
-    } while(0);
-    $cmp395 = ($41|0)==(0|0);
-    if (!($cmp395)) {
-     $index399 = ((($add$ptr6)) + 28|0);
-     $52 = HEAP32[$index399>>2]|0;
-     $arrayidx400 = (480 + ($52<<2)|0);
-     $53 = HEAP32[$arrayidx400>>2]|0;
-     $cmp401 = ($add$ptr6|0)==($53|0);
-     if ($cmp401) {
-      HEAP32[$arrayidx400>>2] = $R332$3;
-      $cond292 = ($R332$3|0)==(0|0);
-      if ($cond292) {
-       $shl408 = 1 << $52;
-       $neg409 = $shl408 ^ -1;
-       $54 = HEAP32[(180)>>2]|0;
-       $and410 = $54 & $neg409;
-       HEAP32[(180)>>2] = $and410;
-       break;
-      }
-     } else {
-      $55 = HEAP32[(192)>>2]|0;
-      $cmp413 = ($41>>>0)<($55>>>0);
-      if ($cmp413) {
-       _abort();
-       // unreachable;
-      }
-      $arrayidx419 = ((($41)) + 16|0);
-      $56 = HEAP32[$arrayidx419>>2]|0;
-      $cmp420 = ($56|0)==($add$ptr6|0);
-      if ($cmp420) {
-       HEAP32[$arrayidx419>>2] = $R332$3;
-      } else {
-       $arrayidx427 = ((($41)) + 20|0);
-       HEAP32[$arrayidx427>>2] = $R332$3;
-      }
-      $cmp432 = ($R332$3|0)==(0|0);
-      if ($cmp432) {
-       break;
-      }
-     }
-     $57 = HEAP32[(192)>>2]|0;
-     $cmp435 = ($R332$3>>>0)<($57>>>0);
-     if ($cmp435) {
-      _abort();
-      // unreachable;
-     }
-     $parent442 = ((($R332$3)) + 24|0);
-     HEAP32[$parent442>>2] = $41;
-     $child443 = ((($add$ptr6)) + 16|0);
-     $58 = HEAP32[$child443>>2]|0;
-     $cmp445 = ($58|0)==(0|0);
-     do {
-      if (!($cmp445)) {
-       $cmp448 = ($58>>>0)<($57>>>0);
-       if ($cmp448) {
-        _abort();
-        // unreachable;
-       } else {
-        $arrayidx454 = ((($R332$3)) + 16|0);
-        HEAP32[$arrayidx454>>2] = $58;
-        $parent455 = ((($58)) + 24|0);
-        HEAP32[$parent455>>2] = $R332$3;
-        break;
-       }
-      }
-     } while(0);
-     $arrayidx460 = ((($child443)) + 4|0);
-     $59 = HEAP32[$arrayidx460>>2]|0;
-     $cmp461 = ($59|0)==(0|0);
-     if (!($cmp461)) {
-      $60 = HEAP32[(192)>>2]|0;
-      $cmp464 = ($59>>>0)<($60>>>0);
-      if ($cmp464) {
-       _abort();
-       // unreachable;
-      } else {
-       $arrayidx470 = ((($R332$3)) + 20|0);
-       HEAP32[$arrayidx470>>2] = $59;
-       $parent471 = ((($59)) + 24|0);
-       HEAP32[$parent471>>2] = $R332$3;
-       break;
-      }
-     }
-    }
-   }
-  } while(0);
-  $or480 = $add267 | 1;
-  $head481 = ((($p$1)) + 4|0);
-  HEAP32[$head481>>2] = $or480;
-  $add$ptr482 = (($p$1) + ($add267)|0);
-  HEAP32[$add$ptr482>>2] = $add267;
-  $61 = HEAP32[(196)>>2]|0;
-  $cmp484 = ($p$1|0)==($61|0);
-  if ($cmp484) {
-   HEAP32[(184)>>2] = $add267;
-   return;
-  } else {
-   $psize$2 = $add267;
-  }
- } else {
-  $and495 = $28 & -2;
-  HEAP32[$head231>>2] = $and495;
-  $or496 = $psize$1 | 1;
-  $head497 = ((($p$1)) + 4|0);
-  HEAP32[$head497>>2] = $or496;
-  $add$ptr498 = (($p$1) + ($psize$1)|0);
-  HEAP32[$add$ptr498>>2] = $psize$1;
-  $psize$2 = $psize$1;
- }
- $shr501 = $psize$2 >>> 3;
- $cmp502 = ($psize$2>>>0)<(256);
- if ($cmp502) {
-  $shl508 = $shr501 << 1;
-  $arrayidx509 = (216 + ($shl508<<2)|0);
-  $62 = HEAP32[44]|0;
-  $shl511 = 1 << $shr501;
-  $and512 = $62 & $shl511;
-  $tobool513 = ($and512|0)==(0);
-  if ($tobool513) {
-   $or516 = $62 | $shl511;
-   HEAP32[44] = $or516;
-   $$pre = ((($arrayidx509)) + 8|0);
-   $$pre$phiZ2D = $$pre;$F510$0 = $arrayidx509;
-  } else {
-   $63 = ((($arrayidx509)) + 8|0);
-   $64 = HEAP32[$63>>2]|0;
-   $65 = HEAP32[(192)>>2]|0;
-   $cmp519 = ($64>>>0)<($65>>>0);
-   if ($cmp519) {
-    _abort();
-    // unreachable;
-   } else {
-    $$pre$phiZ2D = $63;$F510$0 = $64;
-   }
-  }
-  HEAP32[$$pre$phiZ2D>>2] = $p$1;
-  $bk529 = ((($F510$0)) + 12|0);
-  HEAP32[$bk529>>2] = $p$1;
-  $fd530 = ((($p$1)) + 8|0);
-  HEAP32[$fd530>>2] = $F510$0;
-  $bk531 = ((($p$1)) + 12|0);
-  HEAP32[$bk531>>2] = $arrayidx509;
-  return;
- }
- $shr535 = $psize$2 >>> 8;
- $cmp536 = ($shr535|0)==(0);
- if ($cmp536) {
-  $I534$0 = 0;
- } else {
-  $cmp540 = ($psize$2>>>0)>(16777215);
-  if ($cmp540) {
-   $I534$0 = 31;
-  } else {
-   $sub = (($shr535) + 1048320)|0;
-   $shr544 = $sub >>> 16;
-   $and545 = $shr544 & 8;
-   $shl546 = $shr535 << $and545;
-   $sub547 = (($shl546) + 520192)|0;
-   $shr548 = $sub547 >>> 16;
-   $and549 = $shr548 & 4;
-   $add550 = $and549 | $and545;
-   $shl551 = $shl546 << $and549;
-   $sub552 = (($shl551) + 245760)|0;
-   $shr553 = $sub552 >>> 16;
-   $and554 = $shr553 & 2;
-   $add555 = $add550 | $and554;
-   $sub556 = (14 - ($add555))|0;
-   $shl557 = $shl551 << $and554;
-   $shr558 = $shl557 >>> 15;
-   $add559 = (($sub556) + ($shr558))|0;
-   $shl560 = $add559 << 1;
-   $add561 = (($add559) + 7)|0;
-   $shr562 = $psize$2 >>> $add561;
-   $and563 = $shr562 & 1;
-   $add564 = $and563 | $shl560;
-   $I534$0 = $add564;
-  }
- }
- $arrayidx567 = (480 + ($I534$0<<2)|0);
- $index568 = ((($p$1)) + 28|0);
- HEAP32[$index568>>2] = $I534$0;
- $child569 = ((($p$1)) + 16|0);
- $arrayidx570 = ((($p$1)) + 20|0);
- HEAP32[$arrayidx570>>2] = 0;
- HEAP32[$child569>>2] = 0;
- $66 = HEAP32[(180)>>2]|0;
- $shl573 = 1 << $I534$0;
- $and574 = $66 & $shl573;
- $tobool575 = ($and574|0)==(0);
- do {
-  if ($tobool575) {
-   $or578 = $66 | $shl573;
-   HEAP32[(180)>>2] = $or578;
-   HEAP32[$arrayidx567>>2] = $p$1;
-   $parent579 = ((($p$1)) + 24|0);
-   HEAP32[$parent579>>2] = $arrayidx567;
-   $bk580 = ((($p$1)) + 12|0);
-   HEAP32[$bk580>>2] = $p$1;
-   $fd581 = ((($p$1)) + 8|0);
-   HEAP32[$fd581>>2] = $p$1;
-  } else {
-   $67 = HEAP32[$arrayidx567>>2]|0;
-   $cmp584 = ($I534$0|0)==(31);
-   $shr586 = $I534$0 >>> 1;
-   $sub589 = (25 - ($shr586))|0;
-   $cond = $cmp584 ? 0 : $sub589;
-   $shl590 = $psize$2 << $cond;
-   $K583$0 = $shl590;$T$0 = $67;
-   while(1) {
-    $head591 = ((($T$0)) + 4|0);
-    $68 = HEAP32[$head591>>2]|0;
-    $and592 = $68 & -8;
-    $cmp593 = ($and592|0)==($psize$2|0);
-    if ($cmp593) {
-     $T$0$lcssa = $T$0;
-     label = 130;
-     break;
-    }
-    $shr596 = $K583$0 >>> 31;
-    $arrayidx599 = (((($T$0)) + 16|0) + ($shr596<<2)|0);
-    $shl600 = $K583$0 << 1;
-    $69 = HEAP32[$arrayidx599>>2]|0;
-    $cmp601 = ($69|0)==(0|0);
-    if ($cmp601) {
-     $T$0$lcssa319 = $T$0;$arrayidx599$lcssa = $arrayidx599;
-     label = 127;
-     break;
-    } else {
-     $K583$0 = $shl600;$T$0 = $69;
-    }
-   }
-   if ((label|0) == 127) {
-    $70 = HEAP32[(192)>>2]|0;
-    $cmp605 = ($arrayidx599$lcssa>>>0)<($70>>>0);
-    if ($cmp605) {
-     _abort();
-     // unreachable;
-    } else {
-     HEAP32[$arrayidx599$lcssa>>2] = $p$1;
-     $parent610 = ((($p$1)) + 24|0);
-     HEAP32[$parent610>>2] = $T$0$lcssa319;
-     $bk611 = ((($p$1)) + 12|0);
-     HEAP32[$bk611>>2] = $p$1;
-     $fd612 = ((($p$1)) + 8|0);
-     HEAP32[$fd612>>2] = $p$1;
-     break;
-    }
-   }
-   else if ((label|0) == 130) {
-    $fd620 = ((($T$0$lcssa)) + 8|0);
-    $71 = HEAP32[$fd620>>2]|0;
-    $72 = HEAP32[(192)>>2]|0;
-    $cmp624 = ($71>>>0)>=($72>>>0);
-    $not$cmp621 = ($T$0$lcssa>>>0)>=($72>>>0);
-    $73 = $cmp624 & $not$cmp621;
-    if ($73) {
-     $bk631 = ((($71)) + 12|0);
-     HEAP32[$bk631>>2] = $p$1;
-     HEAP32[$fd620>>2] = $p$1;
-     $fd633 = ((($p$1)) + 8|0);
-     HEAP32[$fd633>>2] = $71;
-     $bk634 = ((($p$1)) + 12|0);
-     HEAP32[$bk634>>2] = $T$0$lcssa;
-     $parent635 = ((($p$1)) + 24|0);
-     HEAP32[$parent635>>2] = 0;
-     break;
-    } else {
-     _abort();
-     // unreachable;
-    }
-   }
-  }
- } while(0);
- $74 = HEAP32[(208)>>2]|0;
- $dec = (($74) + -1)|0;
- HEAP32[(208)>>2] = $dec;
- $cmp640 = ($dec|0)==(0);
- if ($cmp640) {
-  $sp$0$in$i = (632);
- } else {
-  return;
- }
- while(1) {
-  $sp$0$i = HEAP32[$sp$0$in$i>>2]|0;
-  $cmp$i = ($sp$0$i|0)==(0|0);
-  $next4$i = ((($sp$0$i)) + 8|0);
-  if ($cmp$i) {
-   break;
-  } else {
-   $sp$0$in$i = $next4$i;
-  }
- }
- HEAP32[(208)>>2] = -1;
- return;
-}
-function runPostSets() {
-}
-function _i64Subtract(a, b, c, d) {
-    a = a|0; b = b|0; c = c|0; d = d|0;
-    var l = 0, h = 0;
-    l = (a - c)>>>0;
-    h = (b - d)>>>0;
-    h = (b - d - (((c>>>0) > (a>>>0))|0))>>>0; // Borrow one from high word to low word on underflow.
-    return ((tempRet0 = h,l|0)|0);
-}
-function _i64Add(a, b, c, d) {
-    /*
-      x = a + b*2^32
-      y = c + d*2^32
-      result = l + h*2^32
-    */
-    a = a|0; b = b|0; c = c|0; d = d|0;
-    var l = 0, h = 0;
-    l = (a + c)>>>0;
-    h = (b + d + (((l>>>0) < (a>>>0))|0))>>>0; // Add carry from low word to high word on overflow.
-    return ((tempRet0 = h,l|0)|0);
-}
-function _memset(ptr, value, num) {
-    ptr = ptr|0; value = value|0; num = num|0;
-    var stop = 0, value4 = 0, stop4 = 0, unaligned = 0;
-    stop = (ptr + num)|0;
-    if ((num|0) >= 20) {
-      // This is unaligned, but quite large, so work hard to get to aligned settings
-      value = value & 0xff;
-      unaligned = ptr & 3;
-      value4 = value | (value << 8) | (value << 16) | (value << 24);
-      stop4 = stop & ~3;
-      if (unaligned) {
-        unaligned = (ptr + 4 - unaligned)|0;
-        while ((ptr|0) < (unaligned|0)) { // no need to check for stop, since we have large num
-          HEAP8[((ptr)>>0)]=value;
-          ptr = (ptr+1)|0;
-        }
-      }
-      while ((ptr|0) < (stop4|0)) {
-        HEAP32[((ptr)>>2)]=value4;
-        ptr = (ptr+4)|0;
-      }
-    }
-    while ((ptr|0) < (stop|0)) {
-      HEAP8[((ptr)>>0)]=value;
-      ptr = (ptr+1)|0;
-    }
-    return (ptr-num)|0;
-}
-function _bitshift64Lshr(low, high, bits) {
-    low = low|0; high = high|0; bits = bits|0;
-    var ander = 0;
-    if ((bits|0) < 32) {
-      ander = ((1 << bits) - 1)|0;
-      tempRet0 = high >>> bits;
-      return (low >>> bits) | ((high&ander) << (32 - bits));
-    }
-    tempRet0 = 0;
-    return (high >>> (bits - 32))|0;
-}
-function _bitshift64Shl(low, high, bits) {
-    low = low|0; high = high|0; bits = bits|0;
-    var ander = 0;
-    if ((bits|0) < 32) {
-      ander = ((1 << bits) - 1)|0;
-      tempRet0 = (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits));
-      return low << bits;
-    }
-    tempRet0 = low << (bits - 32);
-    return 0;
-}
-function _memcpy(dest, src, num) {
-    dest = dest|0; src = src|0; num = num|0;
-    var ret = 0;
-    if ((num|0) >= 4096) return _emscripten_memcpy_big(dest|0, src|0, num|0)|0;
-    ret = dest|0;
-    if ((dest&3) == (src&3)) {
-      while (dest & 3) {
-        if ((num|0) == 0) return ret|0;
-        HEAP8[((dest)>>0)]=((HEAP8[((src)>>0)])|0);
-        dest = (dest+1)|0;
-        src = (src+1)|0;
-        num = (num-1)|0;
-      }
-      while ((num|0) >= 4) {
-        HEAP32[((dest)>>2)]=((HEAP32[((src)>>2)])|0);
-        dest = (dest+4)|0;
-        src = (src+4)|0;
-        num = (num-4)|0;
-      }
-    }
-    while ((num|0) > 0) {
-      HEAP8[((dest)>>0)]=((HEAP8[((src)>>0)])|0);
-      dest = (dest+1)|0;
-      src = (src+1)|0;
-      num = (num-1)|0;
-    }
-    return ret|0;
-}
-function _bitshift64Ashr(low, high, bits) {
-    low = low|0; high = high|0; bits = bits|0;
-    var ander = 0;
-    if ((bits|0) < 32) {
-      ander = ((1 << bits) - 1)|0;
-      tempRet0 = high >> bits;
-      return (low >>> bits) | ((high&ander) << (32 - bits));
-    }
-    tempRet0 = (high|0) < 0 ? -1 : 0;
-    return (high >> (bits - 32))|0;
-  }
-
-// ======== compiled code from system/lib/compiler-rt , see readme therein
-function ___muldsi3($a, $b) {
-  $a = $a | 0;
-  $b = $b | 0;
-  var $1 = 0, $2 = 0, $3 = 0, $6 = 0, $8 = 0, $11 = 0, $12 = 0;
-  $1 = $a & 65535;
-  $2 = $b & 65535;
-  $3 = Math_imul($2, $1) | 0;
-  $6 = $a >>> 16;
-  $8 = ($3 >>> 16) + (Math_imul($2, $6) | 0) | 0;
-  $11 = $b >>> 16;
-  $12 = Math_imul($11, $1) | 0;
-  return (tempRet0 = (($8 >>> 16) + (Math_imul($11, $6) | 0) | 0) + ((($8 & 65535) + $12 | 0) >>> 16) | 0, 0 | ($8 + $12 << 16 | $3 & 65535)) | 0;
-}
-function ___divdi3($a$0, $a$1, $b$0, $b$1) {
-  $a$0 = $a$0 | 0;
-  $a$1 = $a$1 | 0;
-  $b$0 = $b$0 | 0;
-  $b$1 = $b$1 | 0;
-  var $1$0 = 0, $1$1 = 0, $2$0 = 0, $2$1 = 0, $4$0 = 0, $4$1 = 0, $6$0 = 0, $7$0 = 0, $7$1 = 0, $8$0 = 0, $10$0 = 0;
-  $1$0 = $a$1 >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1;
-  $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1;
-  $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1;
-  $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1;
-  $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1) | 0;
-  $4$1 = tempRet0;
-  $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1) | 0;
-  $7$0 = $2$0 ^ $1$0;
-  $7$1 = $2$1 ^ $1$1;
-  $8$0 = ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, 0) | 0;
-  $10$0 = _i64Subtract($8$0 ^ $7$0, tempRet0 ^ $7$1, $7$0, $7$1) | 0;
-  return $10$0 | 0;
-}
-function ___remdi3($a$0, $a$1, $b$0, $b$1) {
-  $a$0 = $a$0 | 0;
-  $a$1 = $a$1 | 0;
-  $b$0 = $b$0 | 0;
-  $b$1 = $b$1 | 0;
-  var $rem = 0, $1$0 = 0, $1$1 = 0, $2$0 = 0, $2$1 = 0, $4$0 = 0, $4$1 = 0, $6$0 = 0, $10$0 = 0, $10$1 = 0, __stackBase__ = 0;
-  __stackBase__ = STACKTOP;
-  STACKTOP = STACKTOP + 16 | 0;
-  $rem = __stackBase__ | 0;
-  $1$0 = $a$1 >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1;
-  $1$1 = (($a$1 | 0) < 0 ? -1 : 0) >> 31 | (($a$1 | 0) < 0 ? -1 : 0) << 1;
-  $2$0 = $b$1 >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1;
-  $2$1 = (($b$1 | 0) < 0 ? -1 : 0) >> 31 | (($b$1 | 0) < 0 ? -1 : 0) << 1;
-  $4$0 = _i64Subtract($1$0 ^ $a$0, $1$1 ^ $a$1, $1$0, $1$1) | 0;
-  $4$1 = tempRet0;
-  $6$0 = _i64Subtract($2$0 ^ $b$0, $2$1 ^ $b$1, $2$0, $2$1) | 0;
-  ___udivmoddi4($4$0, $4$1, $6$0, tempRet0, $rem) | 0;
-  $10$0 = _i64Subtract(HEAP32[$rem >> 2] ^ $1$0, HEAP32[$rem + 4 >> 2] ^ $1$1, $1$0, $1$1) | 0;
-  $10$1 = tempRet0;
-  STACKTOP = __stackBase__;
-  return (tempRet0 = $10$1, $10$0) | 0;
-}
-function ___muldi3($a$0, $a$1, $b$0, $b$1) {
-  $a$0 = $a$0 | 0;
-  $a$1 = $a$1 | 0;
-  $b$0 = $b$0 | 0;
-  $b$1 = $b$1 | 0;
-  var $x_sroa_0_0_extract_trunc = 0, $y_sroa_0_0_extract_trunc = 0, $1$0 = 0, $1$1 = 0, $2 = 0;
-  $x_sroa_0_0_extract_trunc = $a$0;
-  $y_sroa_0_0_extract_trunc = $b$0;
-  $1$0 = ___muldsi3($x_sroa_0_0_extract_trunc, $y_sroa_0_0_extract_trunc) | 0;
-  $1$1 = tempRet0;
-  $2 = Math_imul($a$1, $y_sroa_0_0_extract_trunc) | 0;
-  return (tempRet0 = ((Math_imul($b$1, $x_sroa_0_0_extract_trunc) | 0) + $2 | 0) + $1$1 | $1$1 & 0, 0 | $1$0 & -1) | 0;
-}
-function ___udivdi3($a$0, $a$1, $b$0, $b$1) {
-  $a$0 = $a$0 | 0;
-  $a$1 = $a$1 | 0;
-  $b$0 = $b$0 | 0;
-  $b$1 = $b$1 | 0;
-  var $1$0 = 0;
-  $1$0 = ___udivmoddi4($a$0, $a$1, $b$0, $b$1, 0) | 0;
-  return $1$0 | 0;
-}
-function ___uremdi3($a$0, $a$1, $b$0, $b$1) {
-  $a$0 = $a$0 | 0;
-  $a$1 = $a$1 | 0;
-  $b$0 = $b$0 | 0;
-  $b$1 = $b$1 | 0;
-  var $rem = 0, __stackBase__ = 0;
-  __stackBase__ = STACKTOP;
-  STACKTOP = STACKTOP + 16 | 0;
-  $rem = __stackBase__ | 0;
-  ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) | 0;
-  STACKTOP = __stackBase__;
-  return (tempRet0 = HEAP32[$rem + 4 >> 2] | 0, HEAP32[$rem >> 2] | 0) | 0;
-}
-function ___udivmoddi4($a$0, $a$1, $b$0, $b$1, $rem) {
-  $a$0 = $a$0 | 0;
-  $a$1 = $a$1 | 0;
-  $b$0 = $b$0 | 0;
-  $b$1 = $b$1 | 0;
-  $rem = $rem | 0;
-  var $n_sroa_0_0_extract_trunc = 0, $n_sroa_1_4_extract_shift$0 = 0, $n_sroa_1_4_extract_trunc = 0, $d_sroa_0_0_extract_trunc = 0, $d_sroa_1_4_extract_shift$0 = 0, $d_sroa_1_4_extract_trunc = 0, $4 = 0, $17 = 0, $37 = 0, $49 = 0, $51 = 0, $57 = 0, $58 = 0, $66 = 0, $78 = 0, $86 = 0, $88 = 0, $89 = 0, $91 = 0, $92 = 0, $95 = 0, $105 = 0, $117 = 0, $119 = 0, $125 = 0, $126 = 0, $130 = 0, $q_sroa_1_1_ph = 0, $q_sroa_0_1_ph = 0, $r_sroa_1_1_ph = 0, $r_sroa_0_1_ph = 0, $sr_1_ph = 0, $d_sroa_0_0_insert_insert99$0 = 0, $d_sroa_0_0_insert_insert99$1 = 0, $137$0 = 0, $137$1 = 0, $carry_0203 = 0, $sr_1202 = 0, $r_sroa_0_1201 = 0, $r_sroa_1_1200 = 0, $q_sroa_0_1199 = 0, $q_sroa_1_1198 = 0, $147 = 0, $149 = 0, $r_sroa_0_0_insert_insert42$0 = 0, $r_sroa_0_0_insert_insert42$1 = 0, $150$1 = 0, $151$0 = 0, $152 = 0, $154$0 = 0, $r_sroa_0_0_extract_trunc = 0, $r_sroa_1_4_extract_trunc = 0, $155 = 0, $carry_0_lcssa$0 = 0, $carry_0_lcssa$1 = 0, $r_sroa_0_1_lcssa = 0, $r_sroa_1_1_lcssa = 0, $q_sroa_0_1_lcssa = 0, $q_sroa_1_1_lcssa = 0, $q_sroa_0_0_insert_ext75$0 = 0, $q_sroa_0_0_insert_ext75$1 = 0, $q_sroa_0_0_insert_insert77$1 = 0, $_0$0 = 0, $_0$1 = 0;
-  $n_sroa_0_0_extract_trunc = $a$0;
-  $n_sroa_1_4_extract_shift$0 = $a$1;
-  $n_sroa_1_4_extract_trunc = $n_sroa_1_4_extract_shift$0;
-  $d_sroa_0_0_extract_trunc = $b$0;
-  $d_sroa_1_4_extract_shift$0 = $b$1;
-  $d_sroa_1_4_extract_trunc = $d_sroa_1_4_extract_shift$0;
-  if (($n_sroa_1_4_extract_trunc | 0) == 0) {
-    $4 = ($rem | 0) != 0;
-    if (($d_sroa_1_4_extract_trunc | 0) == 0) {
-      if ($4) {
-        HEAP32[$rem >> 2] = ($n_sroa_0_0_extract_trunc >>> 0) % ($d_sroa_0_0_extract_trunc >>> 0);
-        HEAP32[$rem + 4 >> 2] = 0;
-      }
-      $_0$1 = 0;
-      $_0$0 = ($n_sroa_0_0_extract_trunc >>> 0) / ($d_sroa_0_0_extract_trunc >>> 0) >>> 0;
-      return (tempRet0 = $_0$1, $_0$0) | 0;
-    } else {
-      if (!$4) {
-        $_0$1 = 0;
-        $_0$0 = 0;
-        return (tempRet0 = $_0$1, $_0$0) | 0;
-      }
-      HEAP32[$rem >> 2] = $a$0 & -1;
-      HEAP32[$rem + 4 >> 2] = $a$1 & 0;
-      $_0$1 = 0;
-      $_0$0 = 0;
-      return (tempRet0 = $_0$1, $_0$0) | 0;
-    }
-  }
-  $17 = ($d_sroa_1_4_extract_trunc | 0) == 0;
-  do {
-    if (($d_sroa_0_0_extract_trunc | 0) == 0) {
-      if ($17) {
-        if (($rem | 0) != 0) {
-          HEAP32[$rem >> 2] = ($n_sroa_1_4_extract_trunc >>> 0) % ($d_sroa_0_0_extract_trunc >>> 0);
-          HEAP32[$rem + 4 >> 2] = 0;
-        }
-        $_0$1 = 0;
-        $_0$0 = ($n_sroa_1_4_extract_trunc >>> 0) / ($d_sroa_0_0_extract_trunc >>> 0) >>> 0;
-        return (tempRet0 = $_0$1, $_0$0) | 0;
-      }
-      if (($n_sroa_0_0_extract_trunc | 0) == 0) {
-        if (($rem | 0) != 0) {
-          HEAP32[$rem >> 2] = 0;
-          HEAP32[$rem + 4 >> 2] = ($n_sroa_1_4_extract_trunc >>> 0) % ($d_sroa_1_4_extract_trunc >>> 0);
-        }
-        $_0$1 = 0;
-        $_0$0 = ($n_sroa_1_4_extract_trunc >>> 0) / ($d_sroa_1_4_extract_trunc >>> 0) >>> 0;
-        return (tempRet0 = $_0$1, $_0$0) | 0;
-      }
-      $37 = $d_sroa_1_4_extract_trunc - 1 | 0;
-      if (($37 & $d_sroa_1_4_extract_trunc | 0) == 0) {
-        if (($rem | 0) != 0) {
-          HEAP32[$rem >> 2] = 0 | $a$0 & -1;
-          HEAP32[$rem + 4 >> 2] = $37 & $n_sroa_1_4_extract_trunc | $a$1 & 0;
-        }
-        $_0$1 = 0;
-        $_0$0 = $n_sroa_1_4_extract_trunc >>> ((_llvm_cttz_i32($d_sroa_1_4_extract_trunc | 0) | 0) >>> 0);
-        return (tempRet0 = $_0$1, $_0$0) | 0;
-      }
-      $49 = Math_clz32($d_sroa_1_4_extract_trunc | 0) | 0;
-      $51 = $49 - (Math_clz32($n_sroa_1_4_extract_trunc | 0) | 0) | 0;
-      if ($51 >>> 0 <= 30) {
-        $57 = $51 + 1 | 0;
-        $58 = 31 - $51 | 0;
-        $sr_1_ph = $57;
-        $r_sroa_0_1_ph = $n_sroa_1_4_extract_trunc << $58 | $n_sroa_0_0_extract_trunc >>> ($57 >>> 0);
-        $r_sroa_1_1_ph = $n_sroa_1_4_extract_trunc >>> ($57 >>> 0);
-        $q_sroa_0_1_ph = 0;
-        $q_sroa_1_1_ph = $n_sroa_0_0_extract_trunc << $58;
-        break;
-      }
-      if (($rem | 0) == 0) {
-        $_0$1 = 0;
-        $_0$0 = 0;
-        return (tempRet0 = $_0$1, $_0$0) | 0;
-      }
-      HEAP32[$rem >> 2] = 0 | $a$0 & -1;
-      HEAP32[$rem + 4 >> 2] = $n_sroa_1_4_extract_shift$0 | $a$1 & 0;
-      $_0$1 = 0;
-      $_0$0 = 0;
-      return (tempRet0 = $_0$1, $_0$0) | 0;
-    } else {
-      if (!$17) {
-        $117 = Math_clz32($d_sroa_1_4_extract_trunc | 0) | 0;
-        $119 = $117 - (Math_clz32($n_sroa_1_4_extract_trunc | 0) | 0) | 0;
-        if ($119 >>> 0 <= 31) {
-          $125 = $119 + 1 | 0;
-          $126 = 31 - $119 | 0;
-          $130 = $119 - 31 >> 31;
-          $sr_1_ph = $125;
-          $r_sroa_0_1_ph = $n_sroa_0_0_extract_trunc >>> ($125 >>> 0) & $130 | $n_sroa_1_4_extract_trunc << $126;
-          $r_sroa_1_1_ph = $n_sroa_1_4_extract_trunc >>> ($125 >>> 0) & $130;
-          $q_sroa_0_1_ph = 0;
-          $q_sroa_1_1_ph = $n_sroa_0_0_extract_trunc << $126;
-          break;
-        }
-        if (($rem | 0) == 0) {
-          $_0$1 = 0;
-          $_0$0 = 0;
-          return (tempRet0 = $_0$1, $_0$0) | 0;
-        }
-        HEAP32[$rem >> 2] = 0 | $a$0 & -1;
-        HEAP32[$rem + 4 >> 2] = $n_sroa_1_4_extract_shift$0 | $a$1 & 0;
-        $_0$1 = 0;
-        $_0$0 = 0;
-        return (tempRet0 = $_0$1, $_0$0) | 0;
-      }
-      $66 = $d_sroa_0_0_extract_trunc - 1 | 0;
-      if (($66 & $d_sroa_0_0_extract_trunc | 0) != 0) {
-        $86 = (Math_clz32($d_sroa_0_0_extract_trunc | 0) | 0) + 33 | 0;
-        $88 = $86 - (Math_clz32($n_sroa_1_4_extract_trunc | 0) | 0) | 0;
-        $89 = 64 - $88 | 0;
-        $91 = 32 - $88 | 0;
-        $92 = $91 >> 31;
-        $95 = $88 - 32 | 0;
-        $105 = $95 >> 31;
-        $sr_1_ph = $88;
-        $r_sroa_0_1_ph = $91 - 1 >> 31 & $n_sroa_1_4_extract_trunc >>> ($95 >>> 0) | ($n_sroa_1_4_extract_trunc << $91 | $n_sroa_0_0_extract_trunc >>> ($88 >>> 0)) & $105;
-        $r_sroa_1_1_ph = $105 & $n_sroa_1_4_extract_trunc >>> ($88 >>> 0);
-        $q_sroa_0_1_ph = $n_sroa_0_0_extract_trunc << $89 & $92;
-        $q_sroa_1_1_ph = ($n_sroa_1_4_extract_trunc << $89 | $n_sroa_0_0_extract_trunc >>> ($95 >>> 0)) & $92 | $n_sroa_0_0_extract_trunc << $91 & $88 - 33 >> 31;
-        break;
-      }
-      if (($rem | 0) != 0) {
-        HEAP32[$rem >> 2] = $66 & $n_sroa_0_0_extract_trunc;
-        HEAP32[$rem + 4 >> 2] = 0;
-      }
-      if (($d_sroa_0_0_extract_trunc | 0) == 1) {
-        $_0$1 = $n_sroa_1_4_extract_shift$0 | $a$1 & 0;
-        $_0$0 = 0 | $a$0 & -1;
-        return (tempRet0 = $_0$1, $_0$0) | 0;
-      } else {
-        $78 = _llvm_cttz_i32($d_sroa_0_0_extract_trunc | 0) | 0;
-        $_0$1 = 0 | $n_sroa_1_4_extract_trunc >>> ($78 >>> 0);
-        $_0$0 = $n_sroa_1_4_extract_trunc << 32 - $78 | $n_sroa_0_0_extract_trunc >>> ($78 >>> 0) | 0;
-        return (tempRet0 = $_0$1, $_0$0) | 0;
-      }
-    }
-  } while (0);
-  if (($sr_1_ph | 0) == 0) {
-    $q_sroa_1_1_lcssa = $q_sroa_1_1_ph;
-    $q_sroa_0_1_lcssa = $q_sroa_0_1_ph;
-    $r_sroa_1_1_lcssa = $r_sroa_1_1_ph;
-    $r_sroa_0_1_lcssa = $r_sroa_0_1_ph;
-    $carry_0_lcssa$1 = 0;
-    $carry_0_lcssa$0 = 0;
-  } else {
-    $d_sroa_0_0_insert_insert99$0 = 0 | $b$0 & -1;
-    $d_sroa_0_0_insert_insert99$1 = $d_sroa_1_4_extract_shift$0 | $b$1 & 0;
-    $137$0 = _i64Add($d_sroa_0_0_insert_insert99$0 | 0, $d_sroa_0_0_insert_insert99$1 | 0, -1, -1) | 0;
-    $137$1 = tempRet0;
-    $q_sroa_1_1198 = $q_sroa_1_1_ph;
-    $q_sroa_0_1199 = $q_sroa_0_1_ph;
-    $r_sroa_1_1200 = $r_sroa_1_1_ph;
-    $r_sroa_0_1201 = $r_sroa_0_1_ph;
-    $sr_1202 = $sr_1_ph;
-    $carry_0203 = 0;
-    while (1) {
-      $147 = $q_sroa_0_1199 >>> 31 | $q_sroa_1_1198 << 1;
-      $149 = $carry_0203 | $q_sroa_0_1199 << 1;
-      $r_sroa_0_0_insert_insert42$0 = 0 | ($r_sroa_0_1201 << 1 | $q_sroa_1_1198 >>> 31);
-      $r_sroa_0_0_insert_insert42$1 = $r_sroa_0_1201 >>> 31 | $r_sroa_1_1200 << 1 | 0;
-      _i64Subtract($137$0, $137$1, $r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1) | 0;
-      $150$1 = tempRet0;
-      $151$0 = $150$1 >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1;
-      $152 = $151$0 & 1;
-      $154$0 = _i64Subtract($r_sroa_0_0_insert_insert42$0, $r_sroa_0_0_insert_insert42$1, $151$0 & $d_sroa_0_0_insert_insert99$0, ((($150$1 | 0) < 0 ? -1 : 0) >> 31 | (($150$1 | 0) < 0 ? -1 : 0) << 1) & $d_sroa_0_0_insert_insert99$1) | 0;
-      $r_sroa_0_0_extract_trunc = $154$0;
-      $r_sroa_1_4_extract_trunc = tempRet0;
-      $155 = $sr_1202 - 1 | 0;
-      if (($155 | 0) == 0) {
-        break;
-      } else {
-        $q_sroa_1_1198 = $147;
-        $q_sroa_0_1199 = $149;
-        $r_sroa_1_1200 = $r_sroa_1_4_extract_trunc;
-        $r_sroa_0_1201 = $r_sroa_0_0_extract_trunc;
-        $sr_1202 = $155;
-        $carry_0203 = $152;
-      }
-    }
-    $q_sroa_1_1_lcssa = $147;
-    $q_sroa_0_1_lcssa = $149;
-    $r_sroa_1_1_lcssa = $r_sroa_1_4_extract_trunc;
-    $r_sroa_0_1_lcssa = $r_sroa_0_0_extract_trunc;
-    $carry_0_lcssa$1 = 0;
-    $carry_0_lcssa$0 = $152;
-  }
-  $q_sroa_0_0_insert_ext75$0 = $q_sroa_0_1_lcssa;
-  $q_sroa_0_0_insert_ext75$1 = 0;
-  $q_sroa_0_0_insert_insert77$1 = $q_sroa_1_1_lcssa | $q_sroa_0_0_insert_ext75$1;
-  if (($rem | 0) != 0) {
-    HEAP32[$rem >> 2] = 0 | $r_sroa_0_1_lcssa;
-    HEAP32[$rem + 4 >> 2] = $r_sroa_1_1_lcssa | 0;
-  }
-  $_0$1 = (0 | $q_sroa_0_0_insert_ext75$0) >>> 31 | $q_sroa_0_0_insert_insert77$1 << 1 | ($q_sroa_0_0_insert_ext75$1 << 1 | $q_sroa_0_0_insert_ext75$0 >>> 31) & 0 | $carry_0_lcssa$1;
-  $_0$0 = ($q_sroa_0_0_insert_ext75$0 << 1 | 0 >>> 31) & -2 | $carry_0_lcssa$0;
-  return (tempRet0 = $_0$1, $_0$0) | 0;
-}
-// =======================================================================
-
-
-
-  
-function dynCall_ii(index,a1) {
-  index = index|0;
-  a1=a1|0;
-  return FUNCTION_TABLE_ii[index&1](a1|0)|0;
-}
-
-
-function dynCall_iiii(index,a1,a2,a3) {
-  index = index|0;
-  a1=a1|0; a2=a2|0; a3=a3|0;
-  return FUNCTION_TABLE_iiii[index&7](a1|0,a2|0,a3|0)|0;
-}
-
-
-function dynCall_vi(index,a1) {
-  index = index|0;
-  a1=a1|0;
-  FUNCTION_TABLE_vi[index&7](a1|0);
-}
-
-function b0(p0) {
- p0 = p0|0; nullFunc_ii(0);return 0;
-}
-function b1(p0,p1,p2) {
- p0 = p0|0;p1 = p1|0;p2 = p2|0; nullFunc_iiii(1);return 0;
-}
-function b2(p0) {
- p0 = p0|0; nullFunc_vi(2);
-}
-
-// EMSCRIPTEN_END_FUNCS
-var FUNCTION_TABLE_ii = [b0,___stdio_close];
-var FUNCTION_TABLE_iiii = [b1,b1,___stdout_write,___stdio_seek,___stdio_write,b1,b1,b1];
-var FUNCTION_TABLE_vi = [b2,b2,b2,b2,b2,_cleanup,b2,b2];
-
-  return { _i64Subtract: _i64Subtract, _free: _free, _main: _main, _i64Add: _i64Add, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, _bitshift64Lshr: _bitshift64Lshr, _fflush: _fflush, ___errno_location: ___errno_location, _bitshift64Shl: _bitshift64Shl, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, establishStackSpace: establishStackSpace, setThrew: setThrew, setTempRet0: setTempRet0, getTempRet0: getTempRet0, dynCall_ii: dynCall_ii, dynCall_iiii: dynCall_iiii, dynCall_vi: dynCall_vi, ___udivmoddi4: ___udivmoddi4 };
-})
-;
diff --git a/binaryen/test/empty.asm.js b/binaryen/test/empty.asm.js
deleted file mode 100644
--- a/binaryen/test/empty.asm.js
+++ /dev/null
@@ -1,4 +0,0 @@
-function EmptyModule() {
-    'use asm';
-    return {};
-}
diff --git a/binaryen/test/empty_4GB.asm.js b/binaryen/test/empty_4GB.asm.js
deleted file mode 100644
--- a/binaryen/test/empty_4GB.asm.js
+++ /dev/null
@@ -1,4 +0,0 @@
-function EmptyModule() {
-    'use asm';
-    return {};
-}
diff --git a/binaryen/test/example/c-api-kitchen-sink.c b/binaryen/test/example/c-api-kitchen-sink.c
--- a/binaryen/test/example/c-api-kitchen-sink.c
+++ b/binaryen/test/example/c-api-kitchen-sink.c
@@ -310,7 +310,8 @@
                         temp15 = makeInt32(module, 110), temp16 = makeInt64(module, 111);
   BinaryenExpressionRef externrefExpr = BinaryenRefNull(module, BinaryenTypeExternref());
   BinaryenExpressionRef funcrefExpr = BinaryenRefNull(module, BinaryenTypeFuncref());
-  funcrefExpr = BinaryenRefFunc(module, "kitchen()sinker");
+  funcrefExpr =
+    BinaryenRefFunc(module, "kitchen()sinker", BinaryenTypeFuncref());
   BinaryenExpressionRef exnrefExpr = BinaryenRefNull(module, BinaryenTypeExnref());
   BinaryenExpressionRef i31refExpr = BinaryenI31New(module, makeInt32(module, 1));
 
@@ -434,8 +435,6 @@
     makeUnary(module, BinaryenAllTrueVecI32x4(), v128),
     makeUnary(module, BinaryenBitmaskVecI32x4(), v128),
     makeUnary(module, BinaryenNegVecI64x2(), v128),
-    makeUnary(module, BinaryenAnyTrueVecI64x2(), v128),
-    makeUnary(module, BinaryenAllTrueVecI64x2(), v128),
     makeUnary(module, BinaryenAbsVecF32x4(), v128),
     makeUnary(module, BinaryenNegVecF32x4(), v128),
     makeUnary(module, BinaryenSqrtVecF32x4(), v128),
@@ -580,10 +579,10 @@
     makeBinary(module, BinaryenMaxVecF32x4(), v128),
     makeBinary(module, BinaryenPMinVecF32x4(), v128),
     makeBinary(module, BinaryenPMaxVecF32x4(), v128),
-    makeBinary(module, BinaryenCeilVecF32x4(), v128),
-    makeBinary(module, BinaryenFloorVecF32x4(), v128),
-    makeBinary(module, BinaryenTruncVecF32x4(), v128),
-    makeBinary(module, BinaryenNearestVecF32x4(), v128),
+    makeUnary(module, BinaryenCeilVecF32x4(), v128),
+    makeUnary(module, BinaryenFloorVecF32x4(), v128),
+    makeUnary(module, BinaryenTruncVecF32x4(), v128),
+    makeUnary(module, BinaryenNearestVecF32x4(), v128),
     makeBinary(module, BinaryenAddVecF64x2(), v128),
     makeBinary(module, BinaryenSubVecF64x2(), v128),
     makeBinary(module, BinaryenMulVecF64x2(), v128),
@@ -592,10 +591,10 @@
     makeBinary(module, BinaryenMaxVecF64x2(), v128),
     makeBinary(module, BinaryenPMinVecF64x2(), v128),
     makeBinary(module, BinaryenPMaxVecF64x2(), v128),
-    makeBinary(module, BinaryenCeilVecF64x2(), v128),
-    makeBinary(module, BinaryenFloorVecF64x2(), v128),
-    makeBinary(module, BinaryenTruncVecF64x2(), v128),
-    makeBinary(module, BinaryenNearestVecF64x2(), v128),
+    makeUnary(module, BinaryenCeilVecF64x2(), v128),
+    makeUnary(module, BinaryenFloorVecF64x2(), v128),
+    makeUnary(module, BinaryenTruncVecF64x2(), v128),
+    makeUnary(module, BinaryenNearestVecF64x2(), v128),
     makeBinary(module, BinaryenNarrowSVecI16x8ToVecI8x16(), v128),
     makeBinary(module, BinaryenNarrowUVecI16x8ToVecI8x16(), v128),
     makeBinary(module, BinaryenNarrowSVecI32x4ToVecI16x8(), v128),
@@ -737,15 +736,16 @@
     BinaryenRefIsNull(module, externrefExpr),
     BinaryenRefIsNull(module, funcrefExpr),
     BinaryenRefIsNull(module, exnrefExpr),
-    BinaryenSelect(module,
-                   temp10,
-                   BinaryenRefNull(module, BinaryenTypeFuncref()),
-                   BinaryenRefFunc(module, "kitchen()sinker"),
-                   BinaryenTypeFuncref()),
+    BinaryenSelect(
+      module,
+      temp10,
+      BinaryenRefNull(module, BinaryenTypeFuncref()),
+      BinaryenRefFunc(module, "kitchen()sinker", BinaryenTypeFuncref()),
+      BinaryenTypeFuncref()),
     // GC
     BinaryenRefEq(module,
-      BinaryenRefNull(module, BinaryenTypeEqref()),
-      BinaryenRefNull(module, BinaryenTypeEqref())),
+                  BinaryenRefNull(module, BinaryenTypeEqref()),
+                  BinaryenRefNull(module, BinaryenTypeEqref())),
     // Exception handling
     BinaryenTry(module, tryBody, catchBody),
     // Atomics
@@ -1365,6 +1365,31 @@
   BinaryenModuleDispose(module);
 }
 
+void test_func_opt() {
+  BinaryenModuleRef module = BinaryenModuleCreate();
+  BinaryenType ii_[2] = {BinaryenTypeInt32(), BinaryenTypeInt32()};
+  BinaryenType ii = BinaryenTypeCreate(ii_, 2);
+  BinaryenExpressionRef x = BinaryenConst(module, BinaryenLiteralInt32(1)),
+                        y = BinaryenConst(module, BinaryenLiteralInt32(3));
+  BinaryenExpressionRef add = BinaryenBinary(module, BinaryenAddInt32(), x, y);
+  BinaryenFunctionRef adder = BinaryenAddFunction(
+    module, "adder", BinaryenTypeNone(), BinaryenTypeInt32(), NULL, 0, add);
+
+  puts("module with a function to optimize:");
+  BinaryenModulePrint(module);
+
+  assert(BinaryenModuleValidate(module));
+
+  BinaryenFunctionOptimize(adder, module);
+
+  assert(BinaryenModuleValidate(module));
+
+  puts("optimized:");
+  BinaryenModulePrint(module);
+
+  BinaryenModuleDispose(module);
+}
+
 int main() {
   test_types();
   test_features();
@@ -1376,6 +1401,7 @@
   test_nonvalid();
   test_color_status();
   test_for_each();
+  test_func_opt();
 
   return 0;
 }
diff --git a/binaryen/test/example/c-api-kitchen-sink.txt b/binaryen/test/example/c-api-kitchen-sink.txt
--- a/binaryen/test/example/c-api-kitchen-sink.txt
+++ b/binaryen/test/example/c-api-kitchen-sink.txt
@@ -25,7 +25,7 @@
 BinaryenFeatureMultivalue: 512
 BinaryenFeatureGC: 1024
 BinaryenFeatureMemory64: 2048
-BinaryenFeatureAll: 4095
+BinaryenFeatureAll: 8191
 (f32.neg
  (f32.const -33.61199951171875)
 )
@@ -389,16 +389,6 @@
        )
       )
       (drop
-       (i64x2.any_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.all_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
        (f32x4.abs
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
@@ -1235,26 +1225,22 @@
        )
       )
       (drop
-       (i16x8.lt_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       (f32x4.ceil
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
       )
       (drop
-       (i16x8.lt_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       (f32x4.floor
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
       )
       (drop
-       (i16x8.gt_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       (f32x4.trunc
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
       )
       (drop
-       (i16x8.gt_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       (f32x4.nearest
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
       )
@@ -1307,26 +1293,22 @@
        )
       )
       (drop
-       (i16x8.ge_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       (f64x2.ceil
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
       )
       (drop
-       (i32x4.eq
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       (f64x2.floor
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
       )
       (drop
-       (i32x4.ne
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       (f64x2.trunc
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
       )
       (drop
-       (i32x4.lt_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+       (f64x2.nearest
         (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
        )
       )
@@ -1811,14 +1793,14 @@
        )
       )
       (drop
-       (i32.atomic.wait
+       (memory.atomic.wait32
         (i32.const 0)
         (i32.const 0)
         (i64.const 111)
        )
       )
       (drop
-       (atomic.notify
+       (memory.atomic.notify
         (i32.const 0)
         (i32.const 0)
        )
@@ -2456,5 +2438,22 @@
  )
  (func $fn2
   (nop)
+ )
+)
+module with a function to optimize:
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $adder (result i32)
+  (i32.add
+   (i32.const 1)
+   (i32.const 3)
+  )
+ )
+)
+optimized:
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (func $adder (result i32)
+  (i32.const 4)
  )
 )
diff --git a/binaryen/test/example/c-api-kitchen-sink.txt.txt b/binaryen/test/example/c-api-kitchen-sink.txt.txt
deleted file mode 100644
--- a/binaryen/test/example/c-api-kitchen-sink.txt.txt
+++ /dev/null
@@ -1,2236 +0,0 @@
-(f32.neg
- (f32.const -33.61199951171875)
-)
-(module
- (type $i32_i64_f32_f64_=>_i32 (func (param i32 i64 f32 f64) (result i32)))
- (type $none_=>_none (func))
- (type $i32_=>_none (func (param i32)))
- (type $i32_f64_=>_f32 (func (param i32 f64) (result f32)))
- (import "module" "base" (func $an-imported (param i32 f64) (result f32)))
- (memory $0 (shared 1 256))
- (data (i32.const 10) "hello, world")
- (data passive "I am passive")
- (table $0 1 1 funcref)
- (elem (i32.const 0) "$kitchen()sinker")
- (global $a-global i32 (i32.const 7))
- (global $a-mutable-global (mut f32) (f32.const 7.5))
- (event $a-event (attr 0) (param i32))
- (export "kitchen_sinker" (func "$kitchen()sinker"))
- (export "mem" (memory $0))
- (start $starter)
- (func "$kitchen()sinker" (param $0 i32) (param $1 i64) (param $2 f32) (param $3 f64) (result i32)
-  (local $4 i32)
-  (local $5 exnref)
-  (block $the-body (result i32)
-   (block $the-nothing
-    (drop
-     (block $the-value (result i32)
-      (drop
-       (i32.clz
-        (i32.const -10)
-       )
-      )
-      (drop
-       (i64.ctz
-        (i64.const -22)
-       )
-      )
-      (drop
-       (i32.popcnt
-        (i32.const -10)
-       )
-      )
-      (drop
-       (f32.neg
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (f64.abs
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (f32.ceil
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (f64.floor
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (f32.trunc
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (f32.nearest
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (f64.sqrt
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (i32.eqz
-        (i32.const -10)
-       )
-      )
-      (drop
-       (i64.extend_i32_s
-        (i32.const -10)
-       )
-      )
-      (drop
-       (i64.extend_i32_u
-        (i32.const -10)
-       )
-      )
-      (drop
-       (i32.wrap_i64
-        (i64.const -22)
-       )
-      )
-      (drop
-       (i32.trunc_f32_s
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (i64.trunc_f32_s
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (i32.trunc_f32_u
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (i64.trunc_f32_u
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (i32.trunc_f64_s
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (i64.trunc_f64_s
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (i32.trunc_f64_u
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (i64.trunc_f64_u
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (i32.trunc_sat_f32_s
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (i64.trunc_sat_f32_s
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (i32.trunc_sat_f32_u
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (i64.trunc_sat_f32_u
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (i32.trunc_sat_f64_s
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (i64.trunc_sat_f64_s
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (i32.trunc_sat_f64_u
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (i64.trunc_sat_f64_u
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (i32.reinterpret_f32
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (i64.reinterpret_f64
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (f32.convert_i32_s
-        (i32.const -10)
-       )
-      )
-      (drop
-       (f64.convert_i32_s
-        (i32.const -10)
-       )
-      )
-      (drop
-       (f32.convert_i32_u
-        (i32.const -10)
-       )
-      )
-      (drop
-       (f64.convert_i32_u
-        (i32.const -10)
-       )
-      )
-      (drop
-       (f32.convert_i64_s
-        (i64.const -22)
-       )
-      )
-      (drop
-       (f64.convert_i64_s
-        (i64.const -22)
-       )
-      )
-      (drop
-       (f32.convert_i64_u
-        (i64.const -22)
-       )
-      )
-      (drop
-       (f64.convert_i64_u
-        (i64.const -22)
-       )
-      )
-      (drop
-       (f64.promote_f32
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (f32.demote_f64
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (f32.reinterpret_i32
-        (i32.const -10)
-       )
-      )
-      (drop
-       (f64.reinterpret_i64
-        (i64.const -22)
-       )
-      )
-      (drop
-       (i8x16.splat
-        (i32.const -10)
-       )
-      )
-      (drop
-       (i16x8.splat
-        (i32.const -10)
-       )
-      )
-      (drop
-       (i32x4.splat
-        (i32.const -10)
-       )
-      )
-      (drop
-       (i64x2.splat
-        (i64.const -22)
-       )
-      )
-      (drop
-       (f32x4.splat
-        (f32.const -33.61199951171875)
-       )
-      )
-      (drop
-       (f64x2.splat
-        (f64.const -9005.84)
-       )
-      )
-      (drop
-       (v128.not
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.abs
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.neg
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.any_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.all_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.bitmask
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.abs
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.neg
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.any_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.all_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.bitmask
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.abs
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.neg
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.any_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.all_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.bitmask
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.neg
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.any_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.all_true
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.abs
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.neg
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.sqrt
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.abs
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.neg
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.sqrt
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.trunc_sat_f32x4_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.trunc_sat_f32x4_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.trunc_sat_f64x2_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.trunc_sat_f64x2_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.convert_i32x4_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.convert_i32x4_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.convert_i64x2_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.convert_i64x2_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.widen_low_i8x16_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.widen_high_i8x16_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.widen_low_i8x16_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.widen_high_i8x16_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.widen_low_i16x8_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.widen_high_i16x8_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.widen_low_i16x8_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.widen_high_i16x8_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32.add
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (f64.sub
-        (f64.const -9005.84)
-        (f64.const -9007.33)
-       )
-      )
-      (drop
-       (i32.div_s
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i64.div_u
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (i64.rem_s
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (i32.rem_u
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i32.and
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i64.or
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (i32.xor
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i64.shl
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (i64.shr_u
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (i32.shr_s
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i32.rotl
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i64.rotr
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (f32.div
-        (f32.const -33.61199951171875)
-        (f32.const -62.5)
-       )
-      )
-      (drop
-       (f64.copysign
-        (f64.const -9005.84)
-        (f64.const -9007.33)
-       )
-      )
-      (drop
-       (f32.min
-        (f32.const -33.61199951171875)
-        (f32.const -62.5)
-       )
-      )
-      (drop
-       (f64.max
-        (f64.const -9005.84)
-        (f64.const -9007.33)
-       )
-      )
-      (drop
-       (i32.eq
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (f32.ne
-        (f32.const -33.61199951171875)
-        (f32.const -62.5)
-       )
-      )
-      (drop
-       (i32.lt_s
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i64.lt_u
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (i64.le_s
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (i32.le_u
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i64.gt_s
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (i32.gt_u
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i32.ge_s
-        (i32.const -10)
-        (i32.const -11)
-       )
-      )
-      (drop
-       (i64.ge_u
-        (i64.const -22)
-        (i64.const -23)
-       )
-      )
-      (drop
-       (f32.lt
-        (f32.const -33.61199951171875)
-        (f32.const -62.5)
-       )
-      )
-      (drop
-       (f64.le
-        (f64.const -9005.84)
-        (f64.const -9007.33)
-       )
-      )
-      (drop
-       (f64.gt
-        (f64.const -9005.84)
-        (f64.const -9007.33)
-       )
-      )
-      (drop
-       (f32.ge
-        (f32.const -33.61199951171875)
-        (f32.const -62.5)
-       )
-      )
-      (drop
-       (i8x16.eq
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.ne
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.lt_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.lt_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.gt_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.gt_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.le_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.le_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.ge_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.ge_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.eq
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.ne
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.lt_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.lt_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.gt_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.gt_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.le_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.le_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.ge_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.ge_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.eq
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.ne
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.lt_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.lt_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.gt_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.gt_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.le_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.le_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.ge_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.ge_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.eq
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.ne
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.lt
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.gt
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.le
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.ge
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.eq
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.ne
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.lt
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.gt
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.le
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.ge
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (v128.and
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (v128.or
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (v128.xor
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (v128.andnot
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.add
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.add_saturate_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.add_saturate_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.sub
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.sub_saturate_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.sub_saturate_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.mul
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.min_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.min_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.max_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.max_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.avgr_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.add
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.add_saturate_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.add_saturate_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.sub
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.sub_saturate_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.sub_saturate_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.mul
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.min_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.min_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.max_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.max_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.avgr_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.add
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.sub
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.mul
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.add
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.sub
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.add
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.sub
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.mul
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.min_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.min_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.max_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.max_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.dot_i16x8_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.div
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.min
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.max
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.add
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.sub
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.mul
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.div
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.min
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.max
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.narrow_i16x8_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.narrow_i16x8_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.narrow_i32x4_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.narrow_i32x4_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (v8x16.swizzle
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.extract_lane_s 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.extract_lane_u 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.extract_lane_s 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i16x8.extract_lane_u 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i32x4.extract_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i64x2.extract_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.extract_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.extract_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (i8x16.replace_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 42)
-       )
-      )
-      (drop
-       (i16x8.replace_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 42)
-       )
-      )
-      (drop
-       (i32x4.replace_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 42)
-       )
-      )
-      (drop
-       (i64x2.replace_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i64.const 42)
-       )
-      )
-      (drop
-       (f32x4.replace_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (f32.const 42)
-       )
-      )
-      (drop
-       (f64x2.replace_lane 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (f64.const 42)
-       )
-      )
-      (drop
-       (i8x16.shl
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i8x16.shr_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i8x16.shr_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i16x8.shl
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i16x8.shr_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i16x8.shr_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i32x4.shl
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i32x4.shr_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i32x4.shr_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i64x2.shl
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i64x2.shr_s
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i64x2.shr_u
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (i32.const 1)
-       )
-      )
-      (drop
-       (v8x16.load_splat
-        (i32.const 128)
-       )
-      )
-      (drop
-       (v16x8.load_splat offset=16 align=1
-        (i32.const 128)
-       )
-      )
-      (drop
-       (v32x4.load_splat offset=16
-        (i32.const 128)
-       )
-      )
-      (drop
-       (v64x2.load_splat align=4
-        (i32.const 128)
-       )
-      )
-      (drop
-       (i16x8.load8x8_s
-        (i32.const 128)
-       )
-      )
-      (drop
-       (i16x8.load8x8_u
-        (i32.const 128)
-       )
-      )
-      (drop
-       (i32x4.load16x4_s
-        (i32.const 128)
-       )
-      )
-      (drop
-       (i32x4.load16x4_u
-        (i32.const 128)
-       )
-      )
-      (drop
-       (i64x2.load32x2_s
-        (i32.const 128)
-       )
-      )
-      (drop
-       (i64x2.load32x2_u
-        (i32.const 128)
-       )
-      )
-      (drop
-       (v8x16.shuffle 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (v128.bitselect
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.qfma
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f32x4.qfms
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.qfma
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (drop
-       (f64x2.qfms
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-        (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
-       )
-      )
-      (memory.init 0
-       (i32.const 1024)
-       (i32.const 0)
-       (i32.const 12)
-      )
-      (data.drop 0)
-      (memory.copy
-       (i32.const 2048)
-       (i32.const 1024)
-       (i32.const 12)
-      )
-      (memory.fill
-       (i32.const 0)
-       (i32.const 42)
-       (i32.const 1024)
-      )
-      (block
-      )
-      (if
-       (i32.const 1)
-       (drop
-        (i32.const 2)
-       )
-       (drop
-        (i32.const 3)
-       )
-      )
-      (if
-       (i32.const 4)
-       (drop
-        (i32.const 5)
-       )
-      )
-      (drop
-       (loop $in (result i32)
-        (i32.const 0)
-       )
-      )
-      (drop
-       (loop (result i32)
-        (i32.const 0)
-       )
-      )
-      (drop
-       (br_if $the-value
-        (i32.const 1)
-        (i32.const 0)
-       )
-      )
-      (br_if $the-nothing
-       (i32.const 2)
-      )
-      (br $the-value
-       (i32.const 3)
-      )
-      (br $the-nothing)
-      (br_table $the-value $the-value
-       (i32.const 1)
-       (i32.const 0)
-      )
-      (br_table $the-nothing $the-nothing
-       (i32.const 2)
-      )
-      (drop
-       (i32.eqz
-        (call "$kitchen()sinker"
-         (i32.const 13)
-         (i64.const 37)
-         (f32.const 1.2999999523162842)
-         (f64.const 3.7)
-        )
-       )
-      )
-      (drop
-       (i32.eqz
-        (i32.trunc_f32_s
-         (call $an-imported
-          (i32.const 13)
-          (f64.const 3.7)
-         )
-        )
-       )
-      )
-      (drop
-       (i32.eqz
-        (call_indirect (type $i32_i64_f32_f64_=>_i32)
-         (i32.const 13)
-         (i64.const 37)
-         (f32.const 1.2999999523162842)
-         (f64.const 3.7)
-         (i32.const 2449)
-        )
-       )
-      )
-      (drop
-       (local.get $0)
-      )
-      (local.set $0
-       (i32.const 101)
-      )
-      (drop
-       (local.tee $0
-        (i32.const 102)
-       )
-      )
-      (drop
-       (i32.load
-        (i32.const 1)
-       )
-      )
-      (drop
-       (i64.load16_s offset=2 align=1
-        (i32.const 8)
-       )
-      )
-      (drop
-       (f32.load
-        (i32.const 2)
-       )
-      )
-      (drop
-       (f64.load offset=2
-        (i32.const 9)
-       )
-      )
-      (i32.store
-       (i32.const 10)
-       (i32.const 11)
-      )
-      (i64.store offset=2 align=4
-       (i32.const 110)
-       (i64.const 111)
-      )
-      (drop
-       (select
-        (i32.const 3)
-        (i32.const 5)
-        (i32.const 1)
-       )
-      )
-      (return
-       (i32.const 1337)
-      )
-      (return_call "$kitchen()sinker"
-       (i32.const 13)
-       (i64.const 37)
-       (f32.const 1.2999999523162842)
-       (f64.const 3.7)
-      )
-      (return_call_indirect (type $i32_i64_f32_f64_=>_i32)
-       (i32.const 13)
-       (i64.const 37)
-       (f32.const 1.2999999523162842)
-       (f64.const 3.7)
-       (i32.const 2449)
-      )
-      (drop
-       (ref.is_null
-        (ref.null)
-       )
-      )
-      (drop
-       (ref.is_null
-        (ref.func "$kitchen()sinker")
-       )
-      )
-      (drop
-       (select (result funcref)
-        (ref.null)
-        (ref.func "$kitchen()sinker")
-        (i32.const 1)
-       )
-      )
-      (try
-       (throw $a-event
-        (i32.const 0)
-       )
-       (catch
-        (local.set $5
-         (exnref.pop)
-        )
-        (drop
-         (block $try-block (result i32)
-          (rethrow
-           (br_on_exn $try-block $a-event
-            (local.get $5)
-           )
-          )
-         )
-        )
-       )
-      )
-      (i32.atomic.store
-       (i32.const 0)
-       (i32.atomic.load
-        (i32.const 0)
-       )
-      )
-      (drop
-       (i32.atomic.wait
-        (i32.const 0)
-        (i32.const 0)
-        (i64.const 111)
-       )
-      )
-      (drop
-       (atomic.notify
-        (i32.const 0)
-        (i32.const 0)
-       )
-      )
-      (atomic.fence)
-      (drop
-       (tuple.make
-        (i32.const 13)
-        (i64.const 37)
-        (f32.const 1.2999999523162842)
-        (f64.const 3.7)
-       )
-      )
-      (drop
-       (tuple.extract 2
-        (tuple.make
-         (i32.const 13)
-         (i64.const 37)
-         (f32.const 1.2999999523162842)
-         (f64.const 3.7)
-        )
-       )
-      )
-      (push
-       (i32.pop)
-      )
-      (push
-       (i64.pop)
-      )
-      (push
-       (f32.pop)
-      )
-      (push
-       (f64.pop)
-      )
-      (push
-       (funcref.pop)
-      )
-      (push
-       (externref.pop)
-      )
-      (push
-       (nullref.pop)
-      )
-      (push
-       (exnref.pop)
-      )
-      (push
-       (funcref.pop)
-      )
-      (push
-       (nullref.pop)
-      )
-      (push
-       (exnref.pop)
-      )
-      (nop)
-      (unreachable)
-     )
-    )
-   )
-   (i32.const 42)
-  )
- )
- (func $starter
-  (nop)
- )
-)
-(module
- (type $none_=>_none (func))
- (type $i32_=>_none (func (param i32)))
- (type $none_=>_i32 (func (result i32)))
- (import "module" "check" (func $check (param i32)))
- (func $just-one-block
-  (local $0 i32)
-  (call $check
-   (i32.const 1337)
-  )
- )
- (func $two-blocks
-  (local $0 i32)
-  (block
-   (call $check
-    (i32.const 0)
-   )
-   (call $check
-    (i32.const 1)
-   )
-  )
- )
- (func $two-blocks-plus-code
-  (local $0 i32)
-  (block
-   (block
-    (call $check
-     (i32.const 0)
-    )
-    (drop
-     (i32.const 77)
-    )
-   )
-   (call $check
-    (i32.const 1)
-   )
-  )
- )
- (func $loop
-  (local $0 i32)
-  (loop $shape$0$continue
-   (block
-    (call $check
-     (i32.const 0)
-    )
-    (call $check
-     (i32.const 1)
-    )
-   )
-   (block
-    (br $shape$0$continue)
-   )
-  )
- )
- (func $loop-plus-code
-  (local $0 i32)
-  (loop $shape$0$continue
-   (block
-    (block
-     (call $check
-      (i32.const 0)
-     )
-     (drop
-      (i32.const 33)
-     )
-    )
-    (call $check
-     (i32.const 1)
-    )
-   )
-   (block
-    (drop
-     (i32.const -66)
-    )
-    (br $shape$0$continue)
-   )
-  )
- )
- (func $split
-  (local $0 i32)
-  (call $check
-   (i32.const 0)
-  )
-  (if
-   (i32.const 55)
-   (block
-    (call $check
-     (i32.const 1)
-    )
-   )
-   (block
-    (call $check
-     (i32.const 2)
-    )
-   )
-  )
- )
- (func $split-plus-code
-  (local $0 i32)
-  (call $check
-   (i32.const 0)
-  )
-  (if
-   (i32.const 55)
-   (block
-    (drop
-     (i32.const 10)
-    )
-    (block
-     (call $check
-      (i32.const 1)
-     )
-    )
-   )
-   (block
-    (drop
-     (i32.const 20)
-    )
-    (block
-     (call $check
-      (i32.const 2)
-     )
-    )
-   )
-  )
- )
- (func $if
-  (local $0 i32)
-  (block $block$3$break
-   (call $check
-    (i32.const 0)
-   )
-   (if
-    (i32.const 55)
-    (block
-     (call $check
-      (i32.const 1)
-     )
-     (block
-      (br $block$3$break)
-     )
-    )
-    (br $block$3$break)
-   )
-  )
-  (block
-   (call $check
-    (i32.const 2)
-   )
-  )
- )
- (func $if-plus-code
-  (local $0 i32)
-  (block $block$3$break
-   (call $check
-    (i32.const 0)
-   )
-   (if
-    (i32.const 55)
-    (block
-     (drop
-      (i32.const -1)
-     )
-     (block
-      (call $check
-       (i32.const 1)
-      )
-      (block
-       (drop
-        (i32.const -3)
-       )
-       (br $block$3$break)
-      )
-     )
-    )
-    (block
-     (drop
-      (i32.const -2)
-     )
-     (br $block$3$break)
-    )
-   )
-  )
-  (block
-   (call $check
-    (i32.const 2)
-   )
-  )
- )
- (func $if-else
-  (local $0 i32)
-  (block $block$4$break
-   (call $check
-    (i32.const 0)
-   )
-   (if
-    (i32.const 55)
-    (block
-     (call $check
-      (i32.const 1)
-     )
-     (block
-      (br $block$4$break)
-     )
-    )
-    (block
-     (call $check
-      (i32.const 2)
-     )
-     (block
-      (br $block$4$break)
-     )
-    )
-   )
-  )
-  (block
-   (call $check
-    (i32.const 3)
-   )
-  )
- )
- (func $loop-tail
-  (local $0 i32)
-  (block $block$3$break
-   (loop $shape$0$continue
-    (block
-     (call $check
-      (i32.const 0)
-     )
-     (call $check
-      (i32.const 1)
-     )
-    )
-    (if
-     (i32.const 10)
-     (br $shape$0$continue)
-     (br $block$3$break)
-    )
-   )
-  )
-  (block
-   (call $check
-    (i32.const 2)
-   )
-  )
- )
- (func $nontrivial-loop-plus-phi-to-head
-  (local $0 i32)
-  (block $block$2$break
-   (call $check
-    (i32.const 0)
-   )
-   (block
-    (drop
-     (i32.const 10)
-    )
-    (br $block$2$break)
-   )
-  )
-  (block
-   (block $block$7$break
-    (block $block$4$break
-     (loop $shape$1$continue
-      (block $block$3$break
-       (call $check
-        (i32.const 1)
-       )
-       (if
-        (i32.const -2)
-        (br $block$3$break)
-        (block
-         (drop
-          (i32.const 20)
-         )
-         (br $block$7$break)
-        )
-       )
-      )
-      (block
-       (call $check
-        (i32.const 2)
-       )
-       (if
-        (i32.const -6)
-        (br $block$4$break)
-        (block
-         (drop
-          (i32.const 30)
-         )
-         (br $shape$1$continue)
-        )
-       )
-      )
-     )
-    )
-    (block
-     (block $block$6$break
-      (call $check
-       (i32.const 3)
-      )
-      (if
-       (i32.const -10)
-       (block
-        (call $check
-         (i32.const 4)
-        )
-        (block
-         (br $block$6$break)
-        )
-       )
-       (br $block$6$break)
-      )
-     )
-     (block
-      (call $check
-       (i32.const 5)
-      )
-      (block
-       (drop
-        (i32.const 40)
-       )
-       (br $block$7$break)
-      )
-     )
-    )
-   )
-   (block
-    (call $check
-     (i32.const 6)
-    )
-   )
-  )
- )
- (func $switch
-  (local $0 i32)
-  (call $check
-   (i32.const 0)
-  )
-  (block $switch$1$leave
-   (block $switch$1$default
-    (block $switch$1$case$3
-     (block $switch$1$case$2
-      (br_table $switch$1$default $switch$1$default $switch$1$case$2 $switch$1$default $switch$1$case$3 $switch$1$case$2 $switch$1$default
-       (i32.const -99)
-      )
-     )
-     (block
-      (block
-       (call $check
-        (i32.const 1)
-       )
-      )
-     )
-     (br $switch$1$leave)
-    )
-    (block
-     (drop
-      (i32.const 55)
-     )
-     (block
-      (call $check
-       (i32.const 2)
-      )
-     )
-    )
-    (br $switch$1$leave)
-   )
-   (block
-    (block
-     (call $check
-      (i32.const 3)
-     )
-    )
-   )
-   (br $switch$1$leave)
-  )
- )
- (func $duffs-device
-  (local $0 i32)
-  (local $1 i32)
-  (local $2 i64)
-  (local $3 i32)
-  (local $4 f32)
-  (local $5 f64)
-  (local $6 i32)
-  (block
-   (block $block$3$break
-    (block $block$2$break
-     (call $check
-      (i32.const 0)
-     )
-     (if
-      (i32.const 10)
-      (block
-       (local.set $3
-        (i32.const 2)
-       )
-       (br $block$2$break)
-      )
-      (block
-       (local.set $3
-        (i32.const 3)
-       )
-       (br $block$3$break)
-      )
-     )
-    )
-   )
-  )
-  (loop $shape$1$continue
-   (if
-    (i32.eq
-     (local.get $3)
-     (i32.const 2)
-    )
-    (block
-     (local.set $3
-      (i32.const 0)
-     )
-     (call $check
-      (i32.const 1)
-     )
-     (block
-      (local.set $3
-       (i32.const 3)
-      )
-      (br $shape$1$continue)
-     )
-    )
-    (if
-     (i32.eq
-      (local.get $3)
-      (i32.const 3)
-     )
-     (block
-      (local.set $3
-       (i32.const 0)
-      )
-      (call $check
-       (i32.const 2)
-      )
-      (block
-       (local.set $3
-        (i32.const 2)
-       )
-       (br $shape$1$continue)
-      )
-     )
-    )
-   )
-  )
- )
- (func $return (result i32)
-  (local $0 i32)
-  (block
-   (call $check
-    (i32.const 42)
-   )
-   (return
-    (i32.const 1337)
-   )
-  )
- )
-)
-(module
-)
diff --git a/binaryen/test/example/c-api-unused-mem.txt b/binaryen/test/example/c-api-unused-mem.txt
--- a/binaryen/test/example/c-api-unused-mem.txt
+++ b/binaryen/test/example/c-api-unused-mem.txt
@@ -36,7 +36,7 @@
   (call $main)
  )
 )
-151
+145
 (module
  (type $none_=>_none (func))
  (memory $0 1024 1024)
diff --git a/binaryen/test/example/cpp-unit.cpp b/binaryen/test/example/cpp-unit.cpp
--- a/binaryen/test/example/cpp-unit.cpp
+++ b/binaryen/test/example/cpp-unit.cpp
@@ -4,6 +4,8 @@
 
 #include <ir/bits.h>
 #include <ir/cost.h>
+#include <ir/effects.h>
+#include <pass.h>
 #include <wasm.h>
 
 using namespace wasm;
@@ -543,9 +545,21 @@
   assert_equal(CostAnalyzer(&get).cost, 0);
 }
 
+void test_effects() {
+  PassOptions options;
+  FeatureSet features;
+  // Unreachables trap.
+  Unreachable unreachable;
+  assert_equal(EffectAnalyzer(options, features, &unreachable).trap, true);
+  // Nops... do not.
+  Nop nop;
+  assert_equal(EffectAnalyzer(options, features, &nop).trap, false);
+}
+
 int main() {
   test_bits();
   test_cost();
+  test_effects();
 
   if (failsCount > 0) {
     abort();
diff --git a/binaryen/test/example/hash.cpp b/binaryen/test/example/hash.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/hash.cpp
@@ -0,0 +1,142 @@
+#include <cassert>
+#include <iostream>
+
+#include <ir/utils.h>
+
+using namespace wasm;
+
+#define assertEqual(left, right)                                               \
+  assert(ExpressionAnalyzer::hash(&left) == ExpressionAnalyzer::hash(&right));
+
+#define assertNotEqual(left, right)                                            \
+  assert(ExpressionAnalyzer::hash(&left) != ExpressionAnalyzer::hash(&right));
+
+int main() {
+  {
+    Const x, y;
+    x.set(Literal(int32_t(10)));
+    y.set(Literal(int32_t(10)));
+    assertEqual(x, y);
+  }
+  {
+    // The value matters (with extremely high probability...)
+    Const x, y;
+    x.set(Literal(int32_t(10)));
+    y.set(Literal(int32_t(11)));
+    assertNotEqual(x, y);
+  }
+  {
+    // The type matters.
+    Const x, y;
+    x.set(Literal(int32_t(10)));
+    y.set(Literal(int64_t(10)));
+    assertNotEqual(x, y);
+  }
+  {
+    // Nested child.
+    Drop dx, dy;
+    Const x, y;
+    x.set(Literal(int32_t(10)));
+    y.set(Literal(int32_t(10)));
+    dx.value = &x;
+    dy.value = &y;
+    assertEqual(dx, dy);
+  }
+  {
+    // Nested child.
+    Drop dx, dy;
+    Const x, y;
+    x.set(Literal(int32_t(10)));
+    y.set(Literal(int32_t(11)));
+    dx.value = &x;
+    dy.value = &y;
+    assertNotEqual(dx, dy);
+  }
+  MixedArena arena;
+  {
+    // Blocks
+    Block x(arena);
+    Block y(arena);
+    assertEqual(x, y);
+  }
+  {
+    // Blocks with contents.
+    Block x(arena);
+    Block y(arena);
+    Nop n;
+    y.list.push_back(&n);
+    assertNotEqual(x, y);
+  }
+  {
+    // Blocks with names.
+    Block x(arena);
+    x.name = "foo";
+    Block y(arena);
+    y.name = "foo";
+    assertEqual(x, y);
+  }
+  {
+    // Different block names hash equally - we ignore internal name differences
+    // intentionally.
+    Block x(arena);
+    x.name = "foo";
+    Block y(arena);
+    y.name = "bar";
+    assertEqual(x, y);
+  }
+  {
+    // Different br names are checked relatively as well.
+    Break x;
+    x.name = "foo";
+    Break y;
+    y.name = "bar";
+    Block z(arena);
+    z.name = "foo";
+    z.list.push_back(&x);
+    Block w(arena);
+    w.name = "bar";
+    w.list.push_back(&y);
+    Block outer1(arena);
+    outer1.name = "outer1";
+    outer1.list.push_back(&z);
+    Block outer2(arena);
+    outer2.name = "outer2";
+    outer2.list.push_back(&w);
+    assertEqual(outer1, outer2);
+  }
+  {
+    // But referring to different relative names leads to a difference.
+    Break x;
+    x.name = "outer1"; // instead of x, go to the outer label this time
+    Break y;
+    y.name = "bar";
+    Block z(arena);
+    z.name = "foo";
+    z.list.push_back(&x);
+    Block w(arena);
+    w.name = "bar";
+    w.list.push_back(&y);
+    Block outer1(arena);
+    outer1.name = "outer1";
+    outer1.list.push_back(&z);
+    Block outer2(arena);
+    outer2.name = "outer2";
+    outer2.list.push_back(&w);
+    assertNotEqual(outer1, outer2);
+  }
+  {
+    // Indexes.
+    LocalGet x, y;
+    x.index = 10;
+    y.index = 10;
+    assertEqual(x, y);
+  }
+  {
+    // Indexes.
+    LocalGet x, y;
+    x.index = 10;
+    y.index = 11;
+    assertNotEqual(x, y);
+  }
+  std::cout << "success.\n";
+}
diff --git a/binaryen/test/example/hash.txt b/binaryen/test/example/hash.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/hash.txt
@@ -0,0 +1,1 @@
+success.
diff --git a/binaryen/test/example/module-splitting.cpp b/binaryen/test/example/module-splitting.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/module-splitting.cpp
@@ -0,0 +1,397 @@
+#include <cassert>
+#include <iostream>
+
+#include "ir/module-splitting.h"
+#include "ir/stack-utils.h"
+#include "wasm-features.h"
+#include "wasm-s-parser.h"
+#include "wasm-validator.h"
+#include "wasm.h"
+
+using namespace wasm;
+
+std::unique_ptr<Module> parse(char* module) {
+  auto wasm = std::make_unique<Module>();
+  wasm->features = FeatureSet::All;
+  try {
+    SExpressionParser parser(module);
+    Element& root = *parser.root;
+    SExpressionWasmBuilder builder(*wasm, *root[0], IRProfile::Normal);
+  } catch (ParseException& p) {
+    p.dump(std::cerr);
+    Fatal() << "error in parsing wasm text";
+  }
+  return wasm;
+}
+
+void do_test(const std::set<Name>& keptFuncs, std::string&& module) {
+  WasmValidator validator;
+  bool valid;
+
+  auto primary = parse(&module.front());
+  valid = validator.validate(*primary);
+  assert(valid && "before invalid!");
+
+  std::cout << "Before:\n";
+  std::cout << *primary.get();
+
+  std::cout << "Keeping: ";
+  if (keptFuncs.size()) {
+    auto it = keptFuncs.begin();
+    std::cout << *it++;
+    while (it != keptFuncs.end()) {
+      std::cout << ", " << *it++;
+    }
+  } else {
+    std::cout << "<none>";
+  }
+  std::cout << "\n";
+
+  ModuleSplitting::Config config;
+  config.primaryFuncs = keptFuncs;
+  config.newExportPrefix = "%";
+  auto secondary = splitFunctions(*primary, config);
+
+  std::cout << "After:\n";
+  std::cout << *primary.get();
+  std::cout << "Secondary:\n";
+  std::cout << *secondary.get();
+  std::cout << "\n\n";
+
+  valid = validator.validate(*primary);
+  assert(valid && "after invalid!");
+  valid = validator.validate(*secondary);
+  assert(valid && "secondary invalid!");
+}
+
+int main() {
+  // Trivial module
+  do_test({}, "(module)");
+
+  // Global stuff
+  do_test({}, R"(
+    (module
+     (memory $mem (shared 3 42))
+     (table $tab 3 42 funcref)
+     (global $glob (mut i32) (i32.const 7))
+     (event $e (attr 0) (param i32))
+    ))");
+
+  // Imported global stuff
+  do_test({}, R"(
+    (module
+     (import "env" "mem" (memory $mem (shared 3 42)))
+     (import "env" "tab" (table $tab 3 42 funcref))
+     (import "env" "glob" (global $glob (mut i32)))
+     (import "env" "e" (event $e (attr 0) (param i32)))
+    ))");
+
+  // Exported global stuff
+  do_test({}, R"(
+    (module
+     (memory $mem (shared 3 42))
+     (table $tab 3 42 funcref)
+     (global $glob (mut i32) (i32.const 7))
+     (event $e (attr 0) (param i32))
+     (export "mem" (memory $mem))
+     (export "tab" (table $tab))
+     (export "glob" (global $glob))
+     (export "e" (event $e))
+    ))");
+
+  // Non-deferred function
+  do_test({"foo"}, R"(
+    (module
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Non-deferred exported function
+  do_test({"foo"}, R"(
+    (module
+     (export "foo" (func $foo))
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Non-deferred function in table
+  do_test({"foo"}, R"(
+    (module
+     (table $table 1 funcref)
+     (elem (i32.const 0) $foo)
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Non-deferred function in table at non-const offset
+  do_test({"foo"}, R"(
+    (module
+     (import "env" "base" (global $base i32))
+     (table $table 1 funcref)
+     (elem (global.get $base) $foo)
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Non-deferred imported function
+  do_test({"foo"}, R"(
+    (module
+     (import "env" "foo" (func $foo (param i32) (result i32)))
+    ))");
+
+  // Non-deferred exported imported function in table at a weird offset
+  do_test({"foo"}, R"(
+    (module
+     (import "env" "foo" (func $foo (param i32) (result i32)))
+     (table $table 1000 funcref)
+     (elem (i32.const 42) $foo)
+     (export "foo" (func $foo))
+    ))");
+
+  // Non-deferred exported imported function in table at a non-const offset
+  do_test({"foo"}, R"(
+    (module
+     (import "env" "base" (global $base i32))
+     (import "env" "foo" (func $foo (param i32) (result i32)))
+     (table $table 1000 funcref)
+     (elem (global.get $base) $foo)
+     (export "foo" (func $foo))
+    ))");
+
+  // Deferred function
+  do_test({}, R"(
+    (module
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Deferred exported function
+  do_test({}, R"(
+    (module
+     (export "foo" (func $foo))
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Deferred function in table
+  do_test({}, R"(
+    (module
+     (table $table 1 funcref)
+     (elem (i32.const 0) $foo)
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Deferred exported function in table at a weird offset
+  do_test({}, R"(
+    (module
+     (table $table 1000 funcref)
+     (elem (i32.const 42) $foo)
+     (export "foo" (func $foo))
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Deferred exported function in table at a non-const offset
+  do_test({}, R"(
+    (module
+     (import "env" "base" (global $base i32))
+     (table $table 1000 funcref)
+     (elem (global.get $base) $foo)
+     (export "foo" (func $foo))
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Deferred exported function in table at an offset from a non-const base
+  do_test({"null"}, R"(
+    (module
+     (import "env" "base" (global $base i32))
+     (table $table 1000 funcref)
+     (elem (global.get $base) $null $foo)
+     (export "foo" (func $foo))
+     (func $null)
+     (func $foo (param i32) (result i32)
+      (local.get 0)
+     )
+    ))");
+
+  // Non-deferred function calling non-deferred function
+  do_test({"foo", "bar"}, R"(
+    (module
+     (func $foo
+      (call $bar)
+     )
+     (func $bar
+      (nop)
+     )
+    ))");
+
+  // Deferred function calling non-deferred function
+  do_test({"bar"}, R"(
+    (module
+     (func $foo
+      (call $bar)
+     )
+     (func $bar
+      (nop)
+     )
+    ))");
+
+  // Non-deferred function calling deferred function
+  do_test({"foo"}, R"(
+    (module
+     (func $foo
+      (call $bar)
+     )
+     (func $bar
+      (nop)
+     )
+    ))");
+
+  // Deferred function calling deferred function
+  do_test({}, R"(
+    (module
+     (func $foo
+      (call $bar)
+     )
+     (func $bar
+      (nop)
+     )
+    ))");
+
+  // Deferred function calling non-deferred function with clashing export name
+  do_test({"foo"}, R"(
+    (module
+     (export "%foo" (func $bar))
+     (func $foo
+      (nop)
+     )
+     (func $bar
+      (call $foo)
+     )
+    ))");
+
+  // Mixed table 1
+  do_test({"bar", "quux"}, R"(
+    (module
+     (table $table 4 funcref)
+     (elem (i32.const 0) $foo $bar $baz $quux)
+     (func $foo
+      (nop)
+     )
+     (func $bar
+      (nop)
+     )
+     (func $baz
+      (nop)
+     )
+     (func $quux
+      (nop)
+     )
+    ))");
+
+  // Mixed table 1 with non-const offset
+  do_test({"bar", "quux"}, R"(
+    (module
+     (import "env" "base" (global $base i32))
+     (table $table 4 funcref)
+     (elem (global.get $base) $foo $bar $baz $quux)
+     (func $foo
+      (nop)
+     )
+     (func $bar
+      (nop)
+     )
+     (func $baz
+      (nop)
+     )
+     (func $quux
+      (nop)
+     )
+    ))");
+
+  // Mixed table 2
+  do_test({"baz"}, R"(
+    (module
+     (table $table 4 funcref)
+     (elem (i32.const 0) $foo $bar $baz $quux)
+     (func $foo
+      (nop)
+     )
+     (func $bar
+      (nop)
+     )
+     (func $baz
+      (nop)
+     )
+     (func $quux
+      (nop)
+     )
+    ))");
+
+  // Mixed table 2 with non-const offset
+  do_test({"baz"}, R"(
+    (module
+     (import "env" "base" (global $base i32))
+     (table $table 4 funcref)
+     (elem (global.get $base) $foo $bar $baz $quux)
+     (func $foo
+      (nop)
+     )
+     (func $bar
+      (nop)
+     )
+     (func $baz
+      (nop)
+     )
+     (func $quux
+      (nop)
+     )
+    ))");
+
+  // `foo` is exported both because it is called by `bar` and because it is in a
+  // table gap
+  do_test({"foo"}, R"(
+    (module
+     (import "env" "base" (global $base i32))
+     (table $table 2 funcref)
+     (elem (global.get $base) $foo $bar)
+     (func $foo
+      (nop)
+     )
+     (func $bar
+      (call $foo)
+     )
+    ))");
+
+  // Mutual recursion with table growth
+  do_test({"foo"}, R"(
+    (module
+     (table $table 1 1 funcref)
+     (elem (i32.const 0) $foo)
+     (func $foo (param i32) (result i32)
+      (call $bar (i32.const 0))
+     )
+     (func $bar (param i32) (result i32)
+      (call $foo (i32.const 1))
+     )
+    ))");
+
+  // Multiple exports of a secondary function
+  do_test({}, R"(
+    (module
+     (export "foo1" (func $foo))
+     (export "foo2" (func $foo))
+     (func $foo)
+    ))");
+}
diff --git a/binaryen/test/example/module-splitting.txt b/binaryen/test/example/module-splitting.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/module-splitting.txt
@@ -0,0 +1,981 @@
+Before:
+(module
+)
+Keeping: <none>
+After:
+(module
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+ (export "%memory" (memory $mem))
+ (export "%table" (table $tab))
+ (export "%global" (global $glob))
+ (export "%event" (event $e))
+)
+Secondary:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "primary" "%memory" (memory $mem (shared 3 42)))
+ (import "primary" "%table" (table $tab 3 42 funcref))
+ (import "primary" "%global" (global $glob (mut i32)))
+ (import "primary" "%event" (event $e (attr 0) (param i32)))
+)
+
+
+Before:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "env" "mem" (memory $mem (shared 3 42)))
+ (import "env" "tab" (table $tab 3 42 funcref))
+ (import "env" "glob" (global $glob (mut i32)))
+ (import "env" "e" (event $e (attr 0) (param i32)))
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "env" "mem" (memory $mem (shared 3 42)))
+ (import "env" "tab" (table $tab 3 42 funcref))
+ (import "env" "glob" (global $glob (mut i32)))
+ (import "env" "e" (event $e (attr 0) (param i32)))
+ (export "%memory" (memory $mem))
+ (export "%table" (table $tab))
+ (export "%global" (global $glob))
+ (export "%event" (event $e))
+)
+Secondary:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "primary" "%memory" (memory $mem (shared 3 42)))
+ (import "primary" "%table" (table $tab 3 42 funcref))
+ (import "primary" "%global" (global $glob (mut i32)))
+ (import "primary" "%event" (event $e (attr 0) (param i32)))
+)
+
+
+Before:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+ (export "mem" (memory $mem))
+ (export "tab" (table $tab))
+ (export "glob" (global $glob))
+ (export "e" (event $e))
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (memory $mem (shared 3 42))
+ (table $tab 3 42 funcref)
+ (global $glob (mut i32) (i32.const 7))
+ (event $e (attr 0) (param i32))
+ (export "mem" (memory $mem))
+ (export "tab" (table $tab))
+ (export "glob" (global $glob))
+ (export "e" (event $e))
+)
+Secondary:
+(module
+ (type $i32_=>_none (func (param i32)))
+ (import "primary" "mem" (memory $mem (shared 3 42)))
+ (import "primary" "tab" (table $tab 3 42 funcref))
+ (import "primary" "glob" (global $glob (mut i32)))
+ (import "primary" "e" (event $e (attr 0) (param i32)))
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "foo" (func $foo))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "foo" (func $foo))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1 funcref)
+ (elem (i32.const 0) $foo)
+ (export "%table" (table $table))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Secondary:
+(module
+ (import "primary" "%table" (table $table 1 funcref))
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "base" (global $base i32))
+ (table $table 1 funcref)
+ (elem (global.get $base) $foo)
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "base" (global $base i32))
+ (table $table 1 funcref)
+ (elem (global.get $base) $foo)
+ (export "%table" (table $table))
+ (export "%global" (global $base))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Secondary:
+(module
+ (import "primary" "%table" (table $table 1 funcref))
+ (import "primary" "%global" (global $base i32))
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $foo)
+ (export "foo" (func $foo))
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $foo)
+ (export "foo" (func $foo))
+ (export "%table" (table $table))
+)
+Secondary:
+(module
+ (import "primary" "%table" (table $table 1000 funcref))
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "base" (global $base i32))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (global.get $base) $foo)
+ (export "foo" (func $foo))
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "base" (global $base i32))
+ (import "env" "foo" (func $foo (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (global.get $base) $foo)
+ (export "foo" (func $foo))
+ (export "%table" (table $table))
+ (export "%global" (global $base))
+)
+Secondary:
+(module
+ (import "primary" "%table" (table $table 1000 funcref))
+ (import "primary" "%global" (global $base i32))
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: <none>
+After:
+(module
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (export "foo" (func $foo))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "placeholder" "0" (func $placeholder_0 (param i32) (result i32)))
+ (table $0 1 funcref)
+ (elem (i32.const 0) $placeholder_0)
+ (export "foo" (func $foo))
+ (export "%table" (table $0))
+ (func $foo (param $0 i32) (result i32)
+  (call_indirect (type $i32_=>_i32)
+   (local.get $0)
+   (i32.const 0)
+  )
+ )
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $0 1 funcref))
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "placeholder" "0" (func $placeholder_0 (param i32) (result i32)))
+ (table $table 1 funcref)
+ (elem (i32.const 0) $placeholder_0)
+ (export "%table" (table $table))
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $table 1 funcref))
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $foo)
+ (export "foo" (func $foo))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "placeholder" "42" (func $placeholder_42 (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (i32.const 42) $placeholder_42)
+ (export "foo" (func $foo))
+ (export "%table" (table $table))
+ (func $foo (param $0 i32) (result i32)
+  (call_indirect (type $i32_=>_i32)
+   (local.get $0)
+   (i32.const 42)
+  )
+ )
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $table 1000 funcref))
+ (elem (i32.const 42) $foo)
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "base" (global $base i32))
+ (table $table 1000 funcref)
+ (elem (global.get $base) $foo)
+ (export "foo" (func $foo))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: <none>
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "base" (global $base i32))
+ (import "placeholder" "0" (func $placeholder_0 (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (global.get $base) $placeholder_0)
+ (export "foo" (func $foo))
+ (export "%table" (table $table))
+ (export "%global" (global $base))
+ (func $foo (param $0 i32) (result i32)
+  (call_indirect (type $i32_=>_i32)
+   (local.get $0)
+   (global.get $base)
+  )
+ )
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $table 1000 funcref))
+ (elem (global.get $base) $foo)
+ (import "primary" "%global" (global $base i32))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "env" "base" (global $base i32))
+ (table $table 1000 funcref)
+ (elem (global.get $base) $null $foo)
+ (export "foo" (func $foo))
+ (func $null
+  (nop)
+ )
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+Keeping: null
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_none (func))
+ (import "env" "base" (global $base i32))
+ (import "placeholder" "1" (func $placeholder_1 (param i32) (result i32)))
+ (table $table 1000 funcref)
+ (elem (global.get $base) $null $placeholder_1)
+ (export "foo" (func $foo))
+ (export "%null" (func $null))
+ (export "%table" (table $table))
+ (export "%global" (global $base))
+ (func $null
+  (nop)
+ )
+ (func $foo (param $0 i32) (result i32)
+  (call_indirect (type $i32_=>_i32)
+   (local.get $0)
+   (i32.add
+    (global.get $base)
+    (i32.const 1)
+   )
+  )
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $table 1000 funcref))
+ (elem (global.get $base) $null $foo)
+ (import "primary" "%global" (global $base i32))
+ (import "primary" "%null" (func $null))
+ (func $foo (param $0 i32) (result i32)
+  (local.get $0)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+  (call $bar)
+ )
+ (func $bar
+  (nop)
+ )
+)
+Keeping: bar, foo
+After:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+  (call $bar)
+ )
+ (func $bar
+  (nop)
+ )
+)
+Secondary:
+(module
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+  (call $bar)
+ )
+ (func $bar
+  (nop)
+ )
+)
+Keeping: bar
+After:
+(module
+ (type $none_=>_none (func))
+ (export "%bar" (func $bar))
+ (func $bar
+  (nop)
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%bar" (func $bar))
+ (func $foo
+  (call $bar)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+  (call $bar)
+ )
+ (func $bar
+  (nop)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $none_=>_none (func))
+ (import "placeholder" "0" (func $placeholder_0))
+ (table $0 1 funcref)
+ (elem (i32.const 0) $placeholder_0)
+ (export "%table" (table $0))
+ (func $foo
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $0 1 funcref))
+ (elem (i32.const 0) $bar)
+ (func $bar
+  (nop)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (func $foo
+  (call $bar)
+ )
+ (func $bar
+  (nop)
+ )
+)
+Keeping: <none>
+After:
+(module
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (func $bar
+  (nop)
+ )
+ (func $foo
+  (call $bar)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (export "%foo" (func $bar))
+ (func $foo
+  (nop)
+ )
+ (func $bar
+  (call $foo)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $none_=>_none (func))
+ (import "placeholder" "0" (func $placeholder_0))
+ (table $0 1 funcref)
+ (elem (i32.const 0) $placeholder_0)
+ (export "%foo" (func $bar))
+ (export "%foo_0" (func $foo))
+ (export "%table" (table $0))
+ (func $foo
+  (nop)
+ )
+ (func $bar
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $0 1 funcref))
+ (elem (i32.const 0) $bar)
+ (import "primary" "%foo_0" (func $foo))
+ (func $bar
+  (call $foo)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (table $table 4 funcref)
+ (elem (i32.const 0) $foo $bar $baz $quux)
+ (func $foo
+  (nop)
+ )
+ (func $bar
+  (nop)
+ )
+ (func $baz
+  (nop)
+ )
+ (func $quux
+  (nop)
+ )
+)
+Keeping: bar, quux
+After:
+(module
+ (type $none_=>_none (func))
+ (import "placeholder" "0" (func $placeholder_0))
+ (import "placeholder" "2" (func $placeholder_2))
+ (table $table 4 funcref)
+ (elem (i32.const 0) $placeholder_0 $bar $placeholder_2 $quux)
+ (export "%table" (table $table))
+ (func $bar
+  (nop)
+ )
+ (func $quux
+  (nop)
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $table 4 funcref))
+ (elem (i32.const 0) $foo)
+ (elem (i32.const 2) $baz)
+ (func $baz
+  (nop)
+ )
+ (func $foo
+  (nop)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (import "env" "base" (global $base i32))
+ (table $table 4 funcref)
+ (elem (global.get $base) $foo $bar $baz $quux)
+ (func $foo
+  (nop)
+ )
+ (func $bar
+  (nop)
+ )
+ (func $baz
+  (nop)
+ )
+ (func $quux
+  (nop)
+ )
+)
+Keeping: bar, quux
+After:
+(module
+ (type $none_=>_none (func))
+ (import "env" "base" (global $base i32))
+ (import "placeholder" "0" (func $placeholder_0))
+ (import "placeholder" "2" (func $placeholder_2))
+ (table $table 4 funcref)
+ (elem (global.get $base) $placeholder_0 $bar $placeholder_2 $quux)
+ (export "%bar" (func $bar))
+ (export "%table" (table $table))
+ (export "%global" (global $base))
+ (func $bar
+  (nop)
+ )
+ (func $quux
+  (nop)
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $table 4 funcref))
+ (elem (global.get $base) $foo $bar $baz)
+ (import "primary" "%global" (global $base i32))
+ (import "primary" "%bar" (func $bar))
+ (func $baz
+  (nop)
+ )
+ (func $foo
+  (nop)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (table $table 4 funcref)
+ (elem (i32.const 0) $foo $bar $baz $quux)
+ (func $foo
+  (nop)
+ )
+ (func $bar
+  (nop)
+ )
+ (func $baz
+  (nop)
+ )
+ (func $quux
+  (nop)
+ )
+)
+Keeping: baz
+After:
+(module
+ (type $none_=>_none (func))
+ (import "placeholder" "0" (func $placeholder_0))
+ (import "placeholder" "1" (func $placeholder_1))
+ (import "placeholder" "3" (func $placeholder_3))
+ (table $table 4 funcref)
+ (elem (i32.const 0) $placeholder_0 $placeholder_1 $baz $placeholder_3)
+ (export "%table" (table $table))
+ (func $baz
+  (nop)
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $table 4 funcref))
+ (elem (i32.const 0) $foo $bar)
+ (elem (i32.const 3) $quux)
+ (func $bar
+  (nop)
+ )
+ (func $foo
+  (nop)
+ )
+ (func $quux
+  (nop)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (import "env" "base" (global $base i32))
+ (table $table 4 funcref)
+ (elem (global.get $base) $foo $bar $baz $quux)
+ (func $foo
+  (nop)
+ )
+ (func $bar
+  (nop)
+ )
+ (func $baz
+  (nop)
+ )
+ (func $quux
+  (nop)
+ )
+)
+Keeping: baz
+After:
+(module
+ (type $none_=>_none (func))
+ (import "env" "base" (global $base i32))
+ (import "placeholder" "0" (func $placeholder_0))
+ (import "placeholder" "1" (func $placeholder_1))
+ (import "placeholder" "3" (func $placeholder_3))
+ (table $table 4 funcref)
+ (elem (global.get $base) $placeholder_0 $placeholder_1 $baz $placeholder_3)
+ (export "%baz" (func $baz))
+ (export "%table" (table $table))
+ (export "%global" (global $base))
+ (func $baz
+  (nop)
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $table 4 funcref))
+ (elem (global.get $base) $foo $bar $baz $quux)
+ (import "primary" "%global" (global $base i32))
+ (import "primary" "%baz" (func $baz))
+ (func $bar
+  (nop)
+ )
+ (func $foo
+  (nop)
+ )
+ (func $quux
+  (nop)
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (import "env" "base" (global $base i32))
+ (table $table 2 funcref)
+ (elem (global.get $base) $foo $bar)
+ (func $foo
+  (nop)
+ )
+ (func $bar
+  (call $foo)
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $none_=>_none (func))
+ (import "env" "base" (global $base i32))
+ (import "placeholder" "1" (func $placeholder_1))
+ (table $table 2 funcref)
+ (elem (global.get $base) $foo $placeholder_1)
+ (export "%foo" (func $foo))
+ (export "%table" (table $table))
+ (export "%global" (global $base))
+ (func $foo
+  (nop)
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $table 2 funcref))
+ (elem (global.get $base) $foo $bar)
+ (import "primary" "%global" (global $base i32))
+ (import "primary" "%foo" (func $foo))
+ (func $bar
+  (call $foo)
+ )
+)
+
+
+Before:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (table $table 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (result i32)
+  (call $bar
+   (i32.const 0)
+  )
+ )
+ (func $bar (param $0 i32) (result i32)
+  (call $foo
+   (i32.const 1)
+  )
+ )
+)
+Keeping: foo
+After:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "placeholder" "1" (func $placeholder_1 (param i32) (result i32)))
+ (table $table 2 2 funcref)
+ (elem (i32.const 0) $foo $placeholder_1)
+ (export "%foo" (func $foo))
+ (export "%table" (table $table))
+ (func $foo (param $0 i32) (result i32)
+  (call_indirect (type $i32_=>_i32)
+   (i32.const 0)
+   (i32.const 1)
+  )
+ )
+)
+Secondary:
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "primary" "%table" (table $table 2 2 funcref))
+ (elem (i32.const 1) $bar)
+ (import "primary" "%foo" (func $foo (param i32) (result i32)))
+ (func $bar (param $0 i32) (result i32)
+  (call $foo
+   (i32.const 1)
+  )
+ )
+)
+
+
+Before:
+(module
+ (type $none_=>_none (func))
+ (export "foo1" (func $foo))
+ (export "foo2" (func $foo))
+ (func $foo
+  (nop)
+ )
+)
+Keeping: <none>
+After:
+(module
+ (type $none_=>_none (func))
+ (import "placeholder" "0" (func $placeholder_0))
+ (table $0 1 funcref)
+ (elem (i32.const 0) $placeholder_0)
+ (export "foo1" (func $foo))
+ (export "foo2" (func $foo))
+ (export "%table" (table $0))
+ (func $foo
+  (call_indirect (type $none_=>_none)
+   (i32.const 0)
+  )
+ )
+)
+Secondary:
+(module
+ (type $none_=>_none (func))
+ (import "primary" "%table" (table $0 1 funcref))
+ (elem (i32.const 0) $foo)
+ (func $foo
+  (nop)
+ )
+)
+
+
diff --git a/binaryen/test/example/space.cpp b/binaryen/test/example/space.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/space.cpp
@@ -0,0 +1,115 @@
+#include <cassert>
+#include <iostream>
+
+#include <support/space.h>
+
+using namespace wasm;
+
+using Span = DisjointSpans::Span;
+
+int main() {
+  // No spans
+  {
+    DisjointSpans root;
+    // Nothing in root
+    assert(!root.checkOverlap(Span{0, 100}));
+  }
+  // One span
+  {
+    DisjointSpans root;
+    root.add(Span{0, 100});
+    // It is there
+    assert(root.checkOverlap(Span{0, 100}));
+  }
+  {
+    DisjointSpans root;
+    root.add(Span{40, 60});
+    // Exact match
+    assert(root.checkOverlap(Span{40, 60}));
+    // No overlap
+    assert(!root.checkOverlap(Span{20, 30}));
+    // Touching, but no overlap
+    assert(!root.checkOverlap(Span{20, 40}));
+    // Overlap
+    assert(root.checkOverlap(Span{20, 41}));
+    assert(root.checkOverlap(Span{40, 41}));
+    // Internal
+    assert(root.checkOverlap(Span{45, 50}));
+    // Touches other side
+    assert(root.checkOverlap(Span{45, 60}));
+    // Overlaps on other side
+    assert(root.checkOverlap(Span{45, 70}));
+    // Just inside.
+    assert(root.checkOverlap(Span{59, 60}));
+    // Just outside
+    assert(!root.checkOverlap(Span{60, 61}));
+    // Totally outside
+    assert(!root.checkOverlap(Span{70, 80}));
+  }
+  // Two spans, different subtrees
+  {
+    DisjointSpans root;
+    root.add(Span{30, 40});
+    root.add(Span{60, 70});
+    assert(!root.checkOverlap(Span{10, 20}));
+    assert(!root.checkOverlap(Span{10, 30}));
+    assert(root.checkOverlap(Span{10, 40}));
+    assert(root.checkOverlap(Span{35, 40}));
+    assert(!root.checkOverlap(Span{40, 60}));
+    assert(!root.checkOverlap(Span{45, 55}));
+    assert(root.checkOverlap(Span{50, 61}));
+    assert(root.checkOverlap(Span{50, 100}));
+    assert(root.checkOverlap(Span{60, 70}));
+    assert(root.checkOverlap(Span{60, 61}));
+    assert(!root.checkOverlap(Span{70, 80}));
+    assert(!root.checkOverlap(Span{70, 100}));
+  }
+  // Two spans, same subtree
+  {
+    DisjointSpans root;
+    root.add(Span{30, 40});
+    root.add(Span{40, 45});
+    assert(!root.checkOverlap(Span{10, 20}));
+    assert(!root.checkOverlap(Span{10, 30}));
+    assert(root.checkOverlap(Span{10, 40}));
+    assert(root.checkOverlap(Span{35, 40}));
+    assert(root.checkOverlap(Span{40, 41}));
+    assert(root.checkOverlap(Span{35, 45}));
+    assert(!root.checkOverlap(Span{45, 100}));
+  }
+  // "Pixels"
+  {
+    const int N = 40;
+    for (int i = 0; i < N; i++) {
+      DisjointSpans root;
+      for (int j = 0; j < N; j++) {
+        // add all pixels but the i-th
+        if (j != i) {
+          root.add(Span{j, j + 1});
+        }
+      }
+      for (int j = 0; j < N; j++) {
+        if (j != i) {
+          assert(root.checkOverlap(Span{j, j + 1}));
+        } else {
+          assert(!root.checkOverlap(Span{j, j + 1}));
+        }
+      }
+      assert(root.checkOverlap(Span{10, N + 10}));
+      assert(!root.checkOverlap(Span{N + 10, N + 20}));
+    }
+  }
+  // Large numbers.
+  {
+    DisjointSpans root;
+    assert(!root.checkOverlap(Span{2948, 2949}));
+    root.add(Span{2948, 2949});
+    assert(root.checkOverlap(Span{2948, 2949}));
+    assert(root.checkOverlap(Span{2940, 2949}));
+    assert(root.checkOverlap(Span{2948, 2959}));
+    assert(root.checkOverlap(Span{0, 18766}));
+    assert(!root.checkOverlap(Span{2000, 2001}));
+    assert(!root.checkOverlap(Span{3000, 3001}));
+  }
+  std::cout << "success.\n";
+}
diff --git a/binaryen/test/example/space.txt b/binaryen/test/example/space.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/space.txt
@@ -0,0 +1,1 @@
+success.
diff --git a/binaryen/test/example/stack-utils.cpp b/binaryen/test/example/stack-utils.cpp
--- a/binaryen/test/example/stack-utils.cpp
+++ b/binaryen/test/example/stack-utils.cpp
@@ -5,7 +5,6 @@
 #include "literal.h"
 #include "mixed_arena.h"
 #include "wasm-builder.h"
-#include "wasm-printing.h"
 #include "wasm-type.h"
 #include "wasm.h"
 
@@ -26,11 +25,9 @@
       builder.makeNop(),
     },
     {Type::i32, Type::i64});
-  WasmPrinter::printExpression(block, std::cout);
-  std::cout << "\n";
+  std::cout << *block << '\n';
   StackUtils::removeNops(block);
-  WasmPrinter::printExpression(block, std::cout);
-  std::cout << "\n";
+  std::cout << *block << '\n';
 }
 
 void test_stack_signatures() {
diff --git a/binaryen/test/example/type-builder.cpp b/binaryen/test/example/type-builder.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/type-builder.cpp
@@ -0,0 +1,142 @@
+#include <cassert>
+#include <iostream>
+
+#include "wasm-type.h"
+
+using namespace wasm;
+
+// Construct Signature, Struct, and Array heap types using undefined types.
+void test_builder() {
+  std::cout << ";; Test TypeBuilder\n";
+
+  // (type $sig (func (param (ref $struct)) (result (ref $array) i32)))
+  // (type $struct (struct (field (ref null $array) (mut rtt 0 $array))))
+  // (type $array (array (mut externref)))
+
+  TypeBuilder builder(3);
+
+  Type refSig = builder.getTempRefType(0, NonNullable);
+  Type refStruct = builder.getTempRefType(1, NonNullable);
+  Type refArray = builder.getTempRefType(2, NonNullable);
+  Type refNullArray = builder.getTempRefType(2, Nullable);
+  Type rttArray = builder.getTempRttType(2, 0);
+  Type refNullExt(HeapType::ext, Nullable);
+
+  Signature sig(refStruct, builder.getTempTupleType({refArray, Type::i32}));
+  Struct struct_({Field(refNullArray, Immutable), Field(rttArray, Mutable)});
+  Array array(Field(refNullExt, Mutable));
+
+  std::cout << "Before setting heap types:\n";
+  std::cout << "(ref $sig) => " << refSig << "\n";
+  std::cout << "(ref $struct) => " << refStruct << "\n";
+  std::cout << "(ref $array) => " << refArray << "\n";
+  std::cout << "(ref null $array) => " << refNullArray << "\n";
+  std::cout << "(rtt 0 $array) => " << rttArray << "\n\n";
+
+  builder.setHeapType(0, sig);
+  builder.setHeapType(1, struct_);
+  builder.setHeapType(2, array);
+
+  std::cout << "After setting heap types:\n";
+  std::cout << "(ref $sig) => " << refSig << "\n";
+  std::cout << "(ref $struct) => " << refStruct << "\n";
+  std::cout << "(ref $array) => " << refArray << "\n";
+  std::cout << "(ref null $array) => " << refNullArray << "\n";
+  std::cout << "(rtt 0 $array) => " << rttArray << "\n\n";
+
+  std::vector<HeapType> built = builder.build();
+
+  Type newRefSig = Type(built[0], NonNullable);
+  Type newRefStruct = Type(built[1], NonNullable);
+  Type newRefArray = Type(built[2], NonNullable);
+  Type newRefNullArray = Type(built[2], Nullable);
+  Type newRttArray = Type(Rtt(0, built[2]));
+
+  assert(refSig != newRefSig);
+  assert(refStruct != newRefStruct);
+  assert(refArray != newRefArray);
+  assert(refNullArray != newRefNullArray);
+  assert(rttArray != newRttArray);
+
+  std::cout << "After building types:\n";
+  std::cout << "(ref $sig) => " << newRefSig << "\n";
+  std::cout << "(ref $struct) => " << newRefStruct << "\n";
+  std::cout << "(ref $array) => " << newRefArray << "\n";
+  std::cout << "(ref null $array) => " << newRefNullArray << "\n";
+  std::cout << "(rtt 0 $array) => " << newRttArray << "\n\n";
+}
+
+// Check that the builder works when there are duplicate definitions
+void test_canonicalization() {
+  std::cout << ";; Test canonicalization\n";
+
+  // (type $struct (struct (field (ref null $sig))))
+  // (type $sig (func))
+  HeapType sig = Signature(Type::none, Type::none);
+  HeapType struct_ = Struct({Field(Type(sig, Nullable), Immutable)});
+
+  TypeBuilder builder(4);
+
+  Type tempSigRef1 = builder.getTempRefType(2, Nullable);
+  Type tempSigRef2 = builder.getTempRefType(3, Nullable);
+
+  assert(tempSigRef1 != tempSigRef2);
+  assert(tempSigRef1 != Type(sig, Nullable));
+  assert(tempSigRef2 != Type(sig, Nullable));
+
+  builder.setHeapType(0, Struct({Field(tempSigRef1, Immutable)}));
+  builder.setHeapType(1, Struct({Field(tempSigRef2, Immutable)}));
+  builder.setHeapType(2, Signature(Type::none, Type::none));
+  builder.setHeapType(3, Signature(Type::none, Type::none));
+
+  std::vector<HeapType> built = builder.build();
+
+  assert(built[0] == struct_);
+  assert(built[1] == struct_);
+  assert(built[2] == sig);
+  assert(built[3] == sig);
+}
+
+void test_recursive() {
+  std::cout << ";; Test recursive types\n";
+
+  {
+    // Trivial recursion
+    TypeBuilder builder(1);
+    Type temp = builder.getTempRefType(0, Nullable);
+    builder.setHeapType(0, Signature(Type::none, temp));
+    // std::vector<HeapType> built = builder.build();
+  }
+
+  {
+    // Mutual recursion
+    TypeBuilder builder(2);
+    Type temp0 = builder.getTempRefType(0, Nullable);
+    Type temp1 = builder.getTempRefType(1, Nullable);
+    builder.setHeapType(0, Signature(Type::none, temp1));
+    builder.setHeapType(1, Signature(Type::none, temp0));
+    // std::vector<HeapType> built = builder.build();
+  }
+
+  {
+    // A longer chain of recursion
+    TypeBuilder builder(5);
+    Type temp0 = builder.getTempRefType(0, Nullable);
+    Type temp1 = builder.getTempRefType(1, Nullable);
+    Type temp2 = builder.getTempRefType(2, Nullable);
+    Type temp3 = builder.getTempRefType(3, Nullable);
+    Type temp4 = builder.getTempRefType(4, Nullable);
+    builder.setHeapType(0, Signature(Type::none, temp1));
+    builder.setHeapType(1, Signature(Type::none, temp2));
+    builder.setHeapType(2, Signature(Type::none, temp3));
+    builder.setHeapType(3, Signature(Type::none, temp4));
+    builder.setHeapType(4, Signature(Type::none, temp0));
+    // std::vector<HeapType> built = builder.build();
+  }
+}
+
+int main() {
+  test_builder();
+  test_canonicalization();
+  test_recursive();
+}
diff --git a/binaryen/test/example/type-builder.txt b/binaryen/test/example/type-builder.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/example/type-builder.txt
@@ -0,0 +1,24 @@
+;; Test TypeBuilder
+Before setting heap types:
+(ref $sig) => (ref (func))
+(ref $struct) => (ref (func))
+(ref $array) => (ref (func))
+(ref null $array) => (ref null (func))
+(rtt 0 $array) => (rtt 0 (func))
+
+After setting heap types:
+(ref $sig) => (ref (func (param (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref)))))))) (result (ref (array (mut externref))) i32)))
+(ref $struct) => (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref)))))))
+(ref $array) => (ref (array (mut externref)))
+(ref null $array) => (ref null (array (mut externref)))
+(rtt 0 $array) => (rtt 0 (array (mut externref)))
+
+After building types:
+(ref $sig) => (ref (func (param (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref)))))))) (result (ref (array (mut externref))) i32)))
+(ref $struct) => (ref (struct (field (ref null (array (mut externref))) (mut (rtt 0 (array (mut externref)))))))
+(ref $array) => (ref (array (mut externref)))
+(ref null $array) => (ref null (array (mut externref)))
+(rtt 0 $array) => (rtt 0 (array (mut externref)))
+
+;; Test canonicalization
+;; Test recursive types
diff --git a/binaryen/test/example/typeinfo.cpp b/binaryen/test/example/typeinfo.cpp
--- a/binaryen/test/example/typeinfo.cpp
+++ b/binaryen/test/example/typeinfo.cpp
@@ -7,82 +7,98 @@
 
 void test_compound() {
   {
-    HeapType func(HeapType::FuncKind);
-    assert(Type(func, true).getID() == Type::funcref);
-    assert(Type(func, false).getID() == Type(func, false).getID());
-    assert(Type(func, false).getID() != Type(func, true).getID());
-    HeapType sameFunc(HeapType::FuncKind);
-    assert(Type(func, false).getID() == Type(sameFunc, false).getID());
+    HeapType func(HeapType::func);
+    assert(Type(func, Nullable).getID() == Type::funcref);
+    assert(Type(func, NonNullable).getID() == Type(func, NonNullable).getID());
+    assert(Type(func, NonNullable).getID() != Type(func, Nullable).getID());
+    HeapType sameFunc(HeapType::func);
+    assert(Type(func, NonNullable).getID() ==
+           Type(sameFunc, NonNullable).getID());
 
-    HeapType extern_(HeapType::ExternKind);
-    assert(Type(extern_, true).getID() == Type::externref);
-    assert(Type(extern_, false).getID() == Type(extern_, false).getID());
-    assert(Type(extern_, false).getID() != Type(extern_, true).getID());
-    HeapType sameExtern(HeapType::ExternKind);
-    assert(Type(extern_, false).getID() == Type(sameExtern, false).getID());
+    HeapType extern_(HeapType::ext);
+    assert(Type(extern_, Nullable).getID() == Type::externref);
+    assert(Type(extern_, NonNullable).getID() ==
+           Type(extern_, NonNullable).getID());
+    assert(Type(extern_, NonNullable).getID() !=
+           Type(extern_, Nullable).getID());
+    HeapType sameExtern(HeapType::ext);
+    assert(Type(extern_, NonNullable).getID() ==
+           Type(sameExtern, NonNullable).getID());
 
-    HeapType exn(HeapType::ExnKind);
-    assert(Type(exn, true).getID() == Type::exnref);
-    assert(Type(exn, false).getID() == Type(exn, false).getID());
-    assert(Type(exn, false).getID() != Type(exn, true).getID());
-    HeapType sameExn(HeapType::ExnKind);
-    assert(Type(exn, false).getID() == Type(sameExn, false).getID());
+    HeapType exn(HeapType::exn);
+    assert(Type(exn, Nullable).getID() == Type::exnref);
+    assert(Type(exn, NonNullable).getID() == Type(exn, NonNullable).getID());
+    assert(Type(exn, NonNullable).getID() != Type(exn, Nullable).getID());
+    HeapType sameExn(HeapType::exn);
+    assert(Type(exn, NonNullable).getID() ==
+           Type(sameExn, NonNullable).getID());
 
-    HeapType any(HeapType::AnyKind);
-    assert(Type(any, true).getID() == Type::anyref);
-    assert(Type(any, false).getID() == Type(any, false).getID());
-    assert(Type(any, false).getID() != Type(any, true).getID());
-    HeapType sameAny(HeapType::AnyKind);
-    assert(Type(any, false).getID() == Type(sameAny, false).getID());
+    HeapType any(HeapType::any);
+    assert(Type(any, Nullable).getID() == Type::anyref);
+    assert(Type(any, NonNullable).getID() == Type(any, NonNullable).getID());
+    assert(Type(any, NonNullable).getID() != Type(any, Nullable).getID());
+    HeapType sameAny(HeapType::any);
+    assert(Type(any, NonNullable).getID() ==
+           Type(sameAny, NonNullable).getID());
 
-    HeapType eq(HeapType::EqKind);
-    // assert(Type(eq, true).getID() == Type::eqref);
-    assert(Type(eq, false).getID() == Type(eq, false).getID());
-    assert(Type(eq, false).getID() != Type(eq, true).getID());
-    HeapType sameEq(HeapType::EqKind);
-    assert(Type(eq, false).getID() == Type(sameEq, false).getID());
+    HeapType eq(HeapType::eq);
+    // assert(Type(eq, Nullable).getID() == Type::eqref);
+    assert(Type(eq, NonNullable).getID() == Type(eq, NonNullable).getID());
+    assert(Type(eq, NonNullable).getID() != Type(eq, Nullable).getID());
+    HeapType sameEq(HeapType::eq);
+    assert(Type(eq, NonNullable).getID() == Type(sameEq, NonNullable).getID());
 
-    HeapType i31(HeapType::I31Kind);
-    // assert(Type(i31, false).getID() == Type::i31ref);
-    assert(Type(i31, false).getID() == Type(i31, false).getID());
-    assert(Type(i31, false).getID() != Type(i31, true).getID());
-    HeapType sameI31(HeapType::I31Kind);
-    assert(Type(i31, false).getID() == Type(sameI31, false).getID());
+    HeapType i31(HeapType::i31);
+    // assert(Type(i31, NonNullable).getID() == Type::i31ref);
+    assert(Type(i31, NonNullable).getID() == Type(i31, NonNullable).getID());
+    assert(Type(i31, NonNullable).getID() != Type(i31, Nullable).getID());
+    HeapType sameI31(HeapType::i31);
+    assert(Type(i31, NonNullable).getID() ==
+           Type(sameI31, NonNullable).getID());
   }
   {
     Signature signature(Type::i32, Type::none);
-    assert(Type(signature, false).getID() == Type(signature, false).getID());
-    assert(Type(signature, false).getID() != Type(signature, true).getID());
+    assert(Type(signature, NonNullable).getID() ==
+           Type(signature, NonNullable).getID());
+    assert(Type(signature, NonNullable).getID() !=
+           Type(signature, Nullable).getID());
 
     Signature sameSignature(Type::i32, Type::none);
-    assert(Type(signature, false).getID() ==
-           Type(sameSignature, false).getID());
+    assert(Type(signature, NonNullable).getID() ==
+           Type(sameSignature, NonNullable).getID());
 
     Signature otherSignature(Type::f64, Type::none);
-    assert(Type(signature, false).getID() !=
-           Type(otherSignature, false).getID());
+    assert(Type(signature, NonNullable).getID() !=
+           Type(otherSignature, NonNullable).getID());
   }
   {
     Struct struct_({});
-    assert(Type(struct_, false).getID() == Type(struct_, false).getID());
-    assert(Type(struct_, false).getID() != Type(struct_, true).getID());
+    assert(Type(struct_, NonNullable).getID() ==
+           Type(struct_, NonNullable).getID());
+    assert(Type(struct_, NonNullable).getID() !=
+           Type(struct_, Nullable).getID());
 
     Struct sameStruct({});
-    assert(Type(struct_, false).getID() == Type(sameStruct, false).getID());
+    assert(Type(struct_, NonNullable).getID() ==
+           Type(sameStruct, NonNullable).getID());
 
-    Struct otherStruct({{Type::i32, false}});
-    assert(Type(struct_, false).getID() != Type(otherStruct, false).getID());
+    Struct otherStruct({{Type::i32, Immutable}});
+    assert(Type(struct_, NonNullable).getID() !=
+           Type(otherStruct, NonNullable).getID());
   }
   {
-    Array array({Type::i32, false});
-    assert(Type(array, false).getID() == Type(array, false).getID());
-    assert(Type(array, false).getID() != Type(array, true).getID());
+    Array array({Type::i32, Immutable});
+    assert(Type(array, NonNullable).getID() ==
+           Type(array, NonNullable).getID());
+    assert(Type(array, NonNullable).getID() != Type(array, Nullable).getID());
 
-    Array sameArray({Type::i32, false});
-    assert(Type(array, false).getID() == Type(sameArray, false).getID());
+    Array sameArray({Type::i32, Immutable});
+    assert(Type(array, NonNullable).getID() ==
+           Type(sameArray, NonNullable).getID());
 
-    Array otherArray({Type::f64, true});
-    assert(Type(array, false).getID() != Type(otherArray, false).getID());
+    Array otherArray({Type::f64, Mutable});
+    assert(Type(array, NonNullable).getID() !=
+           Type(otherArray, NonNullable).getID());
   }
   {
     Tuple singleTuple({Type::i32});
@@ -98,18 +114,18 @@
     assert(Type(tuple).getID() != Type(otherTuple).getID());
   }
   {
-    Rtt rtt(0, HeapType::FuncKind);
+    Rtt rtt(0, HeapType::func);
     assert(Type(rtt).getID() == Type(rtt).getID());
 
-    Rtt sameRtt(0, HeapType::FuncKind);
+    Rtt sameRtt(0, HeapType::func);
     assert(rtt == sameRtt);
     assert(Type(rtt).getID() == Type(sameRtt).getID());
 
-    Rtt otherDepthRtt(1, HeapType::FuncKind);
+    Rtt otherDepthRtt(1, HeapType::func);
     assert(rtt != otherDepthRtt);
     assert(Type(rtt).getID() != Type(otherDepthRtt).getID());
 
-    Rtt otherHeapTypeRtt(0, HeapType::AnyKind);
+    Rtt otherHeapTypeRtt(0, HeapType::any);
     assert(rtt != otherHeapTypeRtt);
     assert(Type(rtt).getID() != Type(otherHeapTypeRtt).getID());
 
@@ -120,7 +136,7 @@
     assert(structRtt == sameStructRtt);
     assert(Type(structRtt).getID() == Type(sameStructRtt).getID());
 
-    Rtt otherStructRtt(0, Struct({{Type::i32, false}}));
+    Rtt otherStructRtt(0, Struct({{Type::i32, Immutable}}));
     assert(structRtt != otherStructRtt);
     assert(Type(structRtt).getID() != Type(otherStructRtt).getID());
   }
@@ -129,66 +145,66 @@
 void test_printing() {
   {
     std::cout << ";; Heap types\n";
-    std::cout << HeapType(HeapType::FuncKind) << "\n";
-    std::cout << Type(HeapType::FuncKind, true) << "\n";
-    std::cout << Type(HeapType::FuncKind, false) << "\n";
-    std::cout << HeapType(HeapType::ExternKind) << "\n";
-    std::cout << Type(HeapType::ExternKind, true) << "\n";
-    std::cout << Type(HeapType::ExternKind, false) << "\n";
-    std::cout << HeapType(HeapType::AnyKind) << "\n";
-    std::cout << Type(HeapType::AnyKind, true) << "\n";
-    std::cout << Type(HeapType::AnyKind, false) << "\n";
-    std::cout << HeapType(HeapType::EqKind) << "\n";
-    std::cout << Type(HeapType::EqKind, true) << "\n";
-    std::cout << Type(HeapType::EqKind, false) << "\n";
-    std::cout << HeapType(HeapType::I31Kind) << "\n";
-    std::cout << Type(HeapType::I31Kind, true) << "\n";
-    std::cout << Type(HeapType::I31Kind, false) << "\n";
-    std::cout << HeapType(HeapType::ExnKind) << "\n";
-    std::cout << Type(HeapType::ExnKind, true) << "\n";
-    std::cout << Type(HeapType::ExnKind, false) << "\n";
+    std::cout << HeapType(HeapType::func) << "\n";
+    std::cout << Type(HeapType::func, Nullable) << "\n";
+    std::cout << Type(HeapType::func, NonNullable) << "\n";
+    std::cout << HeapType(HeapType::ext) << "\n";
+    std::cout << Type(HeapType::ext, Nullable) << "\n";
+    std::cout << Type(HeapType::ext, NonNullable) << "\n";
+    std::cout << HeapType(HeapType::any) << "\n";
+    std::cout << Type(HeapType::any, Nullable) << "\n";
+    std::cout << Type(HeapType::any, NonNullable) << "\n";
+    std::cout << HeapType(HeapType::eq) << "\n";
+    std::cout << Type(HeapType::eq, Nullable) << "\n";
+    std::cout << Type(HeapType::eq, NonNullable) << "\n";
+    std::cout << HeapType(HeapType::i31) << "\n";
+    std::cout << Type(HeapType::i31, Nullable) << "\n";
+    std::cout << Type(HeapType::i31, NonNullable) << "\n";
+    std::cout << HeapType(HeapType::exn) << "\n";
+    std::cout << Type(HeapType::exn, Nullable) << "\n";
+    std::cout << Type(HeapType::exn, NonNullable) << "\n";
     std::cout << HeapType(Signature(Type::none, Type::none)) << "\n";
     std::cout << HeapType(Struct({})) << "\n";
-    std::cout << HeapType(Array({Type::i32, false})) << "\n";
+    std::cout << HeapType(Array({Type::i32, Immutable})) << "\n";
   }
   {
     std::cout << "\n;; Signature\n";
     Signature emptySignature(Type::none, Type::none);
     std::cout << emptySignature << "\n";
-    std::cout << Type(emptySignature, false) << "\n";
-    std::cout << Type(emptySignature, true) << "\n";
+    std::cout << Type(emptySignature, NonNullable) << "\n";
+    std::cout << Type(emptySignature, Nullable) << "\n";
     Signature signature(Type::i32, Type::f64);
     std::cout << signature << "\n";
-    std::cout << Type(signature, false) << "\n";
-    std::cout << Type(signature, true) << "\n";
+    std::cout << Type(signature, NonNullable) << "\n";
+    std::cout << Type(signature, Nullable) << "\n";
   }
   {
     std::cout << "\n;; Struct\n";
     Struct emptyStruct({});
     std::cout << emptyStruct << "\n";
-    std::cout << Type(emptyStruct, false) << "\n";
-    std::cout << Type(emptyStruct, true) << "\n";
+    std::cout << Type(emptyStruct, NonNullable) << "\n";
+    std::cout << Type(emptyStruct, Nullable) << "\n";
     Struct struct_({
-      {Type::i32, false},
-      {Type::i64, false},
-      {Type::f32, true},
-      {Type::f64, true},
-      {Type::externref, false},
+      {Type::i32, Immutable},
+      {Type::i64, Immutable},
+      {Type::f32, Mutable},
+      {Type::f64, Mutable},
+      {Type::externref, Immutable},
     });
     std::cout << struct_ << "\n";
-    std::cout << Type(struct_, false) << "\n";
-    std::cout << Type(struct_, true) << "\n";
+    std::cout << Type(struct_, NonNullable) << "\n";
+    std::cout << Type(struct_, Nullable) << "\n";
   }
   {
     std::cout << "\n;; Array\n";
-    Array array({Type::i32, false});
+    Array array({Type::i32, Immutable});
     std::cout << array << "\n";
-    std::cout << Type(array, false) << "\n";
-    std::cout << Type(array, true) << "\n";
-    Array arrayMut({Type::externref, true});
+    std::cout << Type(array, NonNullable) << "\n";
+    std::cout << Type(array, Nullable) << "\n";
+    Array arrayMut({Type::externref, Mutable});
     std::cout << arrayMut << "\n";
-    std::cout << Type(arrayMut, false) << "\n";
-    std::cout << Type(arrayMut, true) << "\n";
+    std::cout << Type(arrayMut, NonNullable) << "\n";
+    std::cout << Type(arrayMut, Nullable) << "\n";
   }
   {
     std::cout << "\n;; Tuple\n";
@@ -205,110 +221,111 @@
   }
   {
     std::cout << "\n;; Rtt\n";
-    std::cout << Rtt(0, HeapType::FuncKind) << "\n";
-    std::cout << Type(Rtt(0, HeapType::FuncKind)) << "\n";
-    std::cout << Rtt(1, HeapType::ExternKind) << "\n";
-    std::cout << Type(Rtt(1, HeapType::ExternKind)) << "\n";
-    std::cout << Rtt(2, HeapType::AnyKind) << "\n";
-    std::cout << Type(Rtt(2, HeapType::AnyKind)) << "\n";
-    std::cout << Rtt(3, HeapType::EqKind) << "\n";
-    std::cout << Type(Rtt(3, HeapType::EqKind)) << "\n";
-    std::cout << Rtt(4, HeapType::I31Kind) << "\n";
-    std::cout << Type(Rtt(4, HeapType::I31Kind)) << "\n";
-    std::cout << Rtt(5, HeapType::ExnKind) << "\n";
-    std::cout << Type(Rtt(5, HeapType::ExnKind)) << "\n";
+    std::cout << Rtt(0, HeapType::func) << "\n";
+    std::cout << Type(Rtt(0, HeapType::func)) << "\n";
+    std::cout << Rtt(1, HeapType::ext) << "\n";
+    std::cout << Type(Rtt(1, HeapType::ext)) << "\n";
+    std::cout << Rtt(2, HeapType::any) << "\n";
+    std::cout << Type(Rtt(2, HeapType::any)) << "\n";
+    std::cout << Rtt(3, HeapType::eq) << "\n";
+    std::cout << Type(Rtt(3, HeapType::eq)) << "\n";
+    std::cout << Rtt(4, HeapType::i31) << "\n";
+    std::cout << Type(Rtt(4, HeapType::i31)) << "\n";
+    std::cout << Rtt(5, HeapType::exn) << "\n";
+    std::cout << Type(Rtt(5, HeapType::exn)) << "\n";
     Rtt signatureRtt(6, Signature(Type::none, Type::none));
     std::cout << signatureRtt << "\n";
     std::cout << Type(signatureRtt) << "\n";
     Rtt structRtt(7, Struct({}));
     std::cout << structRtt << "\n";
     std::cout << Type(structRtt) << "\n";
-    Rtt arrayRtt(8, Array({Type::i32, false}));
+    Rtt arrayRtt(8, Array({Type::i32, Immutable}));
     std::cout << arrayRtt << "\n";
     std::cout << Type(arrayRtt) << "\n";
   }
   {
     std::cout << "\n;; Signature of references (param/result)\n";
-    Signature signature(Type(Struct({}), true),
-                        Type(Array({Type::i32, true}), false));
+    Signature signature(Type(Struct({}), Nullable),
+                        Type(Array({Type::i32, Mutable}), NonNullable));
     std::cout << signature << "\n";
   }
   {
     std::cout << "\n;; Signature of references (params/results)\n";
     Signature signature(Type({
-                          Type(Struct({}), true),
-                          Type(Array({Type::i32, true}), false),
+                          Type(Struct({}), Nullable),
+                          Type(Array({Type::i32, Mutable}), NonNullable),
                         }),
                         Type({
-                          Type(Struct({}), false),
-                          Type(Array({Type::i32, false}), true),
+                          Type(Struct({}), NonNullable),
+                          Type(Array({Type::i32, Immutable}), Nullable),
                         }));
     std::cout << signature << "\n";
   }
   {
     std::cout << "\n;; Struct of references\n";
     Struct structOfSignature({
-      {Type(Signature(Type::none, Type::none), false), false},
-      {Type(Signature(Type::none, Type::none), false), true},
-      {Type(Signature(Type::none, Type::none), true), false},
-      {Type(Signature(Type::none, Type::none), true), true},
+      {Type(Signature(Type::none, Type::none), NonNullable), Immutable},
+      {Type(Signature(Type::none, Type::none), NonNullable), Mutable},
+      {Type(Signature(Type::none, Type::none), Nullable), Immutable},
+      {Type(Signature(Type::none, Type::none), Nullable), Mutable},
     });
     std::cout << structOfSignature << "\n";
-    std::cout << Type(structOfSignature, false) << "\n";
-    std::cout << Type(structOfSignature, true) << "\n";
+    std::cout << Type(structOfSignature, NonNullable) << "\n";
+    std::cout << Type(structOfSignature, Nullable) << "\n";
     Struct structOfStruct({
-      {Type(Struct({}), false), false},
-      {Type(Struct({}), false), true},
-      {Type(Struct({}), true), false},
-      {Type(Struct({}), true), true},
+      {Type(Struct({}), NonNullable), Immutable},
+      {Type(Struct({}), NonNullable), Mutable},
+      {Type(Struct({}), Nullable), Immutable},
+      {Type(Struct({}), Nullable), Mutable},
     });
     std::cout << structOfStruct << "\n";
-    std::cout << Type(structOfStruct, false) << "\n";
-    std::cout << Type(structOfStruct, true) << "\n";
+    std::cout << Type(structOfStruct, NonNullable) << "\n";
+    std::cout << Type(structOfStruct, Nullable) << "\n";
     Struct structOfArray({
-      {Type(Array({Type::i32, false}), false), false},
-      {Type(Array({Type::i32, false}), false), true},
-      {Type(Array({Type::i32, false}), true), false},
-      {Type(Array({Type::i32, false}), true), true},
+      {Type(Array({Type::i32, Immutable}), NonNullable), Immutable},
+      {Type(Array({Type::i32, Immutable}), NonNullable), Mutable},
+      {Type(Array({Type::i32, Immutable}), Nullable), Immutable},
+      {Type(Array({Type::i32, Immutable}), Nullable), Mutable},
     });
     std::cout << structOfArray << "\n";
-    std::cout << Type(structOfArray, false) << "\n";
-    std::cout << Type(structOfArray, true) << "\n";
+    std::cout << Type(structOfArray, NonNullable) << "\n";
+    std::cout << Type(structOfArray, Nullable) << "\n";
     Struct structOfEverything({
-      {Type::i32, true},
-      {Type(Signature(Type::none, Type::none), true), true},
-      {Type(Struct({}), true), true},
-      {Type(Array({Type::i32, true}), true), true},
+      {Type::i32, Mutable},
+      {Type(Signature(Type::none, Type::none), Nullable), Mutable},
+      {Type(Struct({}), Nullable), Mutable},
+      {Type(Array({Type::i32, Mutable}), Nullable), Mutable},
     });
     std::cout << structOfEverything << "\n";
-    std::cout << Type(structOfEverything, false) << "\n";
-    std::cout << Type(structOfEverything, true) << "\n";
+    std::cout << Type(structOfEverything, NonNullable) << "\n";
+    std::cout << Type(structOfEverything, Nullable) << "\n";
   }
   {
     std::cout << "\n;; Array of references\n";
     Array arrayOfSignature(
-      {Type(Signature(Type::none, Type::none), true), false});
+      {Type(Signature(Type::none, Type::none), Nullable), Immutable});
     std::cout << arrayOfSignature << "\n";
-    std::cout << Type(arrayOfSignature, false) << "\n";
-    std::cout << Type(arrayOfSignature, true) << "\n";
-    Array arrayOfStruct({Type(Struct({}), true), true});
+    std::cout << Type(arrayOfSignature, NonNullable) << "\n";
+    std::cout << Type(arrayOfSignature, Nullable) << "\n";
+    Array arrayOfStruct({Type(Struct({}), Nullable), Mutable});
     std::cout << arrayOfStruct << "\n";
-    std::cout << Type(arrayOfStruct, false) << "\n";
-    std::cout << Type(arrayOfStruct, true) << "\n";
-    Array arrayOfArray({Type(Array({Type::i32, false}), true), false});
+    std::cout << Type(arrayOfStruct, NonNullable) << "\n";
+    std::cout << Type(arrayOfStruct, Nullable) << "\n";
+    Array arrayOfArray(
+      {Type(Array({Type::i32, Immutable}), Nullable), Immutable});
     std::cout << arrayOfArray << "\n";
-    std::cout << Type(arrayOfArray, false) << "\n";
-    std::cout << Type(arrayOfArray, true) << "\n";
+    std::cout << Type(arrayOfArray, NonNullable) << "\n";
+    std::cout << Type(arrayOfArray, Nullable) << "\n";
   }
   {
     std::cout << "\n;; Tuple of references\n";
     Tuple tuple({
-      Type(Signature(Type::none, Type::none), false),
-      Type(Signature(Type::none, Type::none), true),
-      Type(Struct({}), false),
-      Type(Struct({}), true),
-      Type(Array({Type::i32, false}), false),
-      Type(Array({Type::i32, false}), true),
+      Type(Signature(Type::none, Type::none), NonNullable),
+      Type(Signature(Type::none, Type::none), Nullable),
+      Type(Struct({}), NonNullable),
+      Type(Struct({}), Nullable),
+      Type(Array({Type::i32, Immutable}), NonNullable),
+      Type(Array({Type::i32, Immutable}), Nullable),
     });
     std::cout << tuple << "\n";
     std::cout << Type(tuple) << "\n";
@@ -317,16 +334,17 @@
   {
     std::cout << "\n;; Recursive (not really)\n";
     Signature signatureSignature(Type::none, Type::none);
-    signatureSignature.params = Type(signatureSignature, false);
+    signatureSignature.params = Type(signatureSignature, NonNullable);
     //                                ^ copies
     std::cout << signatureSignature << "\n";
-    std::cout << Type(signatureSignature, false) << "\n";
+    std::cout << Type(signatureSignature, NonNullable) << "\n";
     Signature signatureArraySignature(Type::none, Type::none);
     signatureArraySignature.params =
-      Type(Array({Type(signatureArraySignature, false), false}), false);
+      Type(Array({Type(signatureArraySignature, NonNullable), Immutable}),
+           NonNullable);
     //                 ^ copies
     std::cout << signatureArraySignature << "\n";
-    std::cout << Type(signatureArraySignature, false) << "\n";
+    std::cout << Type(signatureArraySignature, NonNullable) << "\n";
   }
 }
 
diff --git a/binaryen/test/export-import.wast.fromBinary.noDebugInfo b/binaryen/test/export-import.wast.fromBinary.noDebugInfo
--- a/binaryen/test/export-import.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/export-import.wast.fromBinary.noDebugInfo
@@ -1,8 +1,8 @@
 (module
  (type $none_=>_none (func))
- (import "env" "test2" (global $gimport$1 i32))
+ (import "env" "test2" (global $gimport$0 i32))
  (import "env" "test1" (func $fimport$0))
  (export "test1" (func $fimport$0))
- (export "test2" (global $gimport$1))
+ (export "test2" (global $gimport$0))
 )
 
diff --git a/binaryen/test/extended-names.wast b/binaryen/test/extended-names.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/extended-names.wast
@@ -0,0 +1,6 @@
+(module $foo
+  (table $t1 1 funcref)
+  (memory $m1 1 1)
+  (data $mydata (i32.const 0) "a")
+  (data $passive_data passive "b")
+)
diff --git a/binaryen/test/extended-names.wast.from-wast b/binaryen/test/extended-names.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/extended-names.wast.from-wast
@@ -0,0 +1,6 @@
+(module $foo
+ (memory $m1 1 1)
+ (data $mydata (i32.const 0) "a")
+ (data $passive_data passive "b")
+ (table $t1 1 funcref)
+)
diff --git a/binaryen/test/extended-names.wast.fromBinary b/binaryen/test/extended-names.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/extended-names.wast.fromBinary
@@ -0,0 +1,7 @@
+(module $foo
+ (memory $m1 1 1)
+ (data $mydata (i32.const 0) "a")
+ (data $passive_data passive "b")
+ (table $t1 1 funcref)
+)
+
diff --git a/binaryen/test/extended-names.wast.fromBinary.noDebugInfo b/binaryen/test/extended-names.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/extended-names.wast.fromBinary.noDebugInfo
@@ -0,0 +1,7 @@
+(module
+ (memory $0 1 1)
+ (data (i32.const 0) "a")
+ (data passive "b")
+ (table $0 1 funcref)
+)
+
diff --git a/binaryen/test/extra-unreachable.wast b/binaryen/test/extra-unreachable.wast
--- a/binaryen/test/extra-unreachable.wast
+++ b/binaryen/test/extra-unreachable.wast
@@ -1,5 +1,5 @@
 (module
-  (type $ii (param i32) (result i32))
+  (type $ii (func (param i32) (result i32)))
   (memory (shared 1 1))
   (table 0 funcref)
   (global $g (mut f32) (f32.const 0))
@@ -86,7 +86,7 @@
       (call $foo (unreachable))
     )
     (global.set $g
-      (call_indirect (type $ii) (unreachable))
+      (call_indirect (type $ii) (unreachable) (unreachable))
     )
 
     ;; unary
@@ -138,16 +138,16 @@
 
     ;; atomic.wait
     (global.set $g
-      (i32.atomic.wait
+      (memory.atomic.wait32
         (unreachable)
         (i32.const 0)
         (i64.const 0)
       )
     )
 
-    ;; atomic.notify
+    ;; memory.atomic.notify
     (global.set $g
-      (atomic.notify
+      (memory.atomic.notify
         (unreachable)
         (i32.const 0)
       )
diff --git a/binaryen/test/extra-unreachable.wast.from-wast b/binaryen/test/extra-unreachable.wast.from-wast
--- a/binaryen/test/extra-unreachable.wast.from-wast
+++ b/binaryen/test/extra-unreachable.wast.from-wast
@@ -1,7 +1,7 @@
 (module
  (type $none_=>_none (func))
- (type $i32_=>_none (func (param i32)))
  (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
  (memory $0 (shared 1 1))
  (table $0 0 funcref)
  (global $g (mut f32) (f32.const 0))
@@ -64,8 +64,9 @@
    )
   )
   (global.set $g
-   (call_indirect (type $none_=>_none)
+   (call_indirect (type $i32_=>_i32)
     (unreachable)
+    (unreachable)
    )
   )
   (global.set $g
@@ -110,14 +111,14 @@
    )
   )
   (global.set $g
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (unreachable)
     (i32.const 0)
     (i64.const 0)
    )
   )
   (global.set $g
-   (atomic.notify
+   (memory.atomic.notify
     (unreachable)
     (i32.const 0)
    )
diff --git a/binaryen/test/fib-dbg.wasm.fromBinary b/binaryen/test/fib-dbg.wasm.fromBinary
--- a/binaryen/test/fib-dbg.wasm.fromBinary
+++ b/binaryen/test/fib-dbg.wasm.fromBinary
@@ -4,8 +4,8 @@
  (type $none_=>_none (func))
  (type $i32_=>_none (func (param i32)))
  (type $none_=>_i32 (func (result i32)))
- (import "env" "memory" (memory $mimport$9 256 256))
- (import "env" "table" (table $timport$10 0 0 funcref))
+ (import "env" "memory" (memory $mimport$0 256 256))
+ (import "env" "table" (table $timport$0 0 0 funcref))
  (import "env" "DYNAMICTOP_PTR" (global $gimport$0 i32))
  (import "env" "tempDoublePtr" (global $gimport$1 i32))
  (import "env" "ABORT" (global $gimport$2 i32))
@@ -15,8 +15,8 @@
  (import "env" "fb" (global $gimport$6 i32))
  (import "global" "NaN" (global $gimport$7 f64))
  (import "global" "Infinity" (global $gimport$8 f64))
- (import "env" "memoryBase" (global $gimport$11 i32))
- (import "env" "tableBase" (global $gimport$12 i32))
+ (import "env" "memoryBase" (global $gimport$9 i32))
+ (import "env" "tableBase" (global $gimport$10 i32))
  (global $global$0 (mut i32) (global.get $gimport$0))
  (global $global$1 (mut i32) (global.get $gimport$1))
  (global $global$2 (mut i32) (global.get $gimport$2))
diff --git a/binaryen/test/gc.wast b/binaryen/test/gc.wast
--- a/binaryen/test/gc.wast
+++ b/binaryen/test/gc.wast
@@ -68,4 +68,9 @@
     (local.set $local_i32 (i31.get_s (local.get $local_i31ref)))
     (local.set $local_i32 (i31.get_u (local.get $local_i31ref)))
   )
+
+  (func $test-variants
+    (local $local_i31refnull (ref null i31))
+    (local $local_i31refnonnull (ref i31))
+  )
 )
diff --git a/binaryen/test/gc.wast.from-wast b/binaryen/test/gc.wast.from-wast
--- a/binaryen/test/gc.wast.from-wast
+++ b/binaryen/test/gc.wast.from-wast
@@ -2,7 +2,7 @@
  (type $none_=>_none (func))
  (global $global_anyref (mut anyref) (ref.null any))
  (global $global_eqref (mut eqref) (ref.null eq))
- (global $global_i31ref (mut i31ref) (i31.new
+ (global $global_i31ref (mut (ref null i31)) (i31.new
   (i32.const 0)
  ))
  (global $global_anyref2 (mut anyref) (ref.null eq))
@@ -16,7 +16,7 @@
   (local $local_i32 i32)
   (local $local_anyref anyref)
   (local $local_eqref eqref)
-  (local $local_i31ref i31ref)
+  (local $local_i31ref (ref null i31))
   (local.set $local_anyref
    (local.get $local_anyref)
   )
@@ -147,5 +147,10 @@
     (local.get $local_i31ref)
    )
   )
+ )
+ (func $test-variants
+  (local $local_i31refnull (ref null i31))
+  (local $local_i31refnonnull (ref null i31))
+  (nop)
  )
 )
diff --git a/binaryen/test/gc.wast.fromBinary b/binaryen/test/gc.wast.fromBinary
--- a/binaryen/test/gc.wast.fromBinary
+++ b/binaryen/test/gc.wast.fromBinary
@@ -2,7 +2,7 @@
  (type $none_=>_none (func))
  (global $global_anyref (mut anyref) (ref.null any))
  (global $global_eqref (mut eqref) (ref.null eq))
- (global $global_i31ref (mut i31ref) (i31.new
+ (global $global_i31ref (mut (ref null i31)) (i31.new
   (i32.const 0)
  ))
  (global $global_anyref2 (mut anyref) (ref.null eq))
@@ -16,7 +16,7 @@
   (local $local_i32 i32)
   (local $local_anyref anyref)
   (local $local_eqref eqref)
-  (local $local_i31ref i31ref)
+  (local $local_i31ref (ref null i31))
   (local.set $local_anyref
    (local.get $local_anyref)
   )
@@ -147,6 +147,11 @@
     (local.get $local_i31ref)
    )
   )
+ )
+ (func $test-variants
+  (local $local_i31refnull (ref null i31))
+  (local $local_i31refnonnull (ref null i31))
+  (nop)
  )
 )
 
diff --git a/binaryen/test/gc.wast.fromBinary.noDebugInfo b/binaryen/test/gc.wast.fromBinary.noDebugInfo
--- a/binaryen/test/gc.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/gc.wast.fromBinary.noDebugInfo
@@ -2,7 +2,7 @@
  (type $none_=>_none (func))
  (global $global$0 (mut anyref) (ref.null any))
  (global $global$1 (mut eqref) (ref.null eq))
- (global $global$2 (mut i31ref) (i31.new
+ (global $global$2 (mut (ref null i31)) (i31.new
   (i32.const 0)
  ))
  (global $global$3 (mut anyref) (ref.null eq))
@@ -16,7 +16,7 @@
   (local $0 i32)
   (local $1 anyref)
   (local $2 eqref)
-  (local $3 i31ref)
+  (local $3 (ref null i31))
   (local.set $1
    (local.get $1)
   )
@@ -147,6 +147,11 @@
     (local.get $3)
    )
   )
+ )
+ (func $1
+  (local $0 (ref null i31))
+  (local $1 (ref null i31))
+  (nop)
  )
 )
 
diff --git a/binaryen/test/heap-types.wast b/binaryen/test/heap-types.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/heap-types.wast
@@ -0,0 +1,185 @@
+;; Test that we can roundtrip struct and array types
+(module
+  ;; Structs
+  (type $struct.A (struct
+    i32
+    (field f32)
+    (field $named f64)
+  ))
+  (type $struct.B (struct
+    (field i8)
+    (field (mut i16))
+    (field (ref $struct.A))
+    (field (mut (ref $struct.A)))
+  ))
+  (type $struct.C (struct
+    (field $named-mut (mut f32))
+  ))
+
+  ;; Arrays
+  (type $vector (array (mut f64)))
+  (type $matrix (array (ref $vector)))
+  (type $bytes (array (mut i8)))
+  (type $words (array (mut i32)))
+
+  ;; RTT
+  (type $parent (struct))
+  (type $child (struct i32))
+  (type $grandchild (struct i32 i64))
+  (global $rttparent (rtt 0 $parent) (rtt.canon $parent))
+  (global $rttchild (rtt 1 $child) (rtt.sub $child (global.get $rttparent)))
+  (global $rttgrandchild (rtt 2 $grandchild) (rtt.sub $grandchild (global.get $rttchild)))
+
+  (func $structs (param $x (ref $struct.A)) (result (ref $struct.B))
+    (local $tA (ref null $struct.A))
+    (local $tB (ref null $struct.B))
+    (local $tc (ref null $struct.C))
+    (local $tv (ref null $vector))
+    (local $tm (ref null $matrix))
+    (drop
+      (local.get $x)
+    )
+    (drop
+      (struct.get $struct.A 0 (local.get $x))
+    )
+    (drop
+      (struct.get $struct.A 1 (local.get $x))
+    )
+    (drop
+      (struct.get $struct.A 2 (local.get $x))
+    )
+    (drop
+      (struct.get $struct.A $named (local.get $x))
+    )
+    (drop
+      (struct.get_u $struct.B 0 (local.get $tB))
+    )
+    (drop
+      (struct.get_s $struct.B 0 (local.get $tB))
+    )
+    (drop
+      (ref.null $struct.A)
+    )
+    (drop
+      (block (result (ref null $struct.A))
+        (local.get $x)
+      )
+    )
+    (drop
+      (if (result (ref null $struct.A))
+        (i32.const 1)
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (loop (result (ref null $struct.A))
+        (local.get $x)
+      )
+    )
+    (drop
+      (select (result (ref null $struct.A))
+        (local.get $x)
+        (local.get $x)
+        (i32.const 1)
+      )
+    )
+    (struct.set $struct.A 0
+      (local.get $x)
+      (i32.const 100)
+    )
+    (drop
+      (struct.new_default_with_rtt $struct.A
+        (rtt.canon $struct.A)
+      )
+    )
+    (drop
+      (struct.new_with_rtt $struct.A
+        (rtt.canon $struct.A)
+        (i32.const 1)
+        (f32.const 2.345)
+        (f64.const 3.14159)
+      )
+    )
+    (unreachable)
+  )
+  (func $arrays (param $x (ref $vector)) (result (ref $matrix))
+    (local $tv (ref null $vector))
+    (local $tm (ref null $matrix))
+    (local $tb (ref null $bytes))
+    (local $tw (ref null $words))
+    (drop
+      (array.new_with_rtt $vector
+        (rtt.canon $vector)
+        (i32.const 3)
+        (f64.const 3.14159)
+      )
+    )
+    (drop
+      (array.new_default_with_rtt $matrix
+        (rtt.canon $matrix)
+        (i32.const 10)
+      )
+    )
+    (drop
+      (array.get $vector
+        (local.get $x)
+        (i32.const 2)
+      )
+    )
+    (array.set $vector
+      (local.get $x)
+      (i32.const 2)
+      (f64.const 2.18281828)
+    )
+    (drop
+      (array.len $vector
+        (local.get $x)
+      )
+    )
+    (drop
+      (array.get $words
+        (local.get $tw)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (array.get_u $bytes
+        (local.get $tb)
+        (i32.const 2)
+      )
+    )
+    (drop
+      (array.get_s $bytes
+        (local.get $tb)
+        (i32.const 3)
+      )
+    )
+    (unreachable)
+  )
+  ;; RTT types as parameters
+  (func $rtt-param-with-depth (param $rtt (rtt 1 $parent)))
+  (func $rtt-param-without-depth (param $rtt (rtt $parent)))
+  (func $rtt-operations
+    (local $temp.A (ref null $struct.A))
+    (drop
+      (ref.test $struct.B (ref.null $struct.A) (rtt.canon $struct.B))
+    )
+    (drop
+      (ref.cast $struct.B (ref.null $struct.A) (rtt.canon $struct.B))
+    )
+    (drop
+      (block $out (result (ref $struct.B))
+        ;; set the value to a local with type $struct.A, showing that the value
+        ;; flowing out has the right type
+        (local.set $temp.A
+          (br_on_cast $out $struct.B (ref.null $struct.A) (rtt.canon $struct.B))
+        )
+        ;; an untaken br_on_cast, with unreachable rtt - so we cannot use the
+        ;; RTT in binaryen IR to find the cast type.
+        (br_on_cast $out $struct.B (ref.null $struct.A) (unreachable))
+        (unreachable)
+      )
+    )
+  )
+)
diff --git a/binaryen/test/heap-types.wast.from-wast b/binaryen/test/heap-types.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/heap-types.wast.from-wast
@@ -0,0 +1,199 @@
+(module
+ (type ${i32_f32_f64} (struct (field i32) (field f32) (field f64)))
+ (type $[mut:f64] (array (mut f64)))
+ (type ${} (struct ))
+ (type $none_=>_none (func))
+ (type ${i32} (struct (field i32)))
+ (type ${i32_i64} (struct (field i32) (field i64)))
+ (type ${mut:f32} (struct (field (mut f32))))
+ (type $[mut:i32] (array (mut i32)))
+ (type $[mut:i8] (array (mut i8)))
+ (type ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref null ${i32_f32_f64})) (field (mut (ref null ${i32_f32_f64})))))
+ (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64])))
+ (type $rtt_1_${}_=>_none (func (param (rtt 1 ${}))))
+ (type $rtt_${}_=>_none (func (param (rtt ${}))))
+ (type $ref?|{i32_f32_f64}|_=>_ref?|{i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}| (func (param (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))))
+ (type $ref?|[mut:f64]|_=>_ref?|[ref?|[mut:f64]|]| (func (param (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|]))))
+ (global $rttparent (rtt 0 ${}) (rtt.canon ${}))
+ (global $rttchild (rtt 1 ${i32}) (rtt.sub ${i32}
+  (global.get $rttparent)
+ ))
+ (global $rttgrandchild (rtt 2 ${i32_i64}) (rtt.sub ${i32_i64}
+  (global.get $rttchild)
+ ))
+ (func $structs (param $x (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))
+  (local $tA (ref null ${i32_f32_f64}))
+  (local $tB (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))
+  (local $tc (ref null ${mut:f32}))
+  (local $tv (ref null $[mut:f64]))
+  (local $tm (ref null $[ref?|[mut:f64]|]))
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 0
+    (local.get $x)
+   )
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 1
+    (local.get $x)
+   )
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 2
+    (local.get $x)
+   )
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 2
+    (local.get $x)
+   )
+  )
+  (drop
+   (struct.get_u ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} 0
+    (local.get $tB)
+   )
+  )
+  (drop
+   (struct.get_s ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} 0
+    (local.get $tB)
+   )
+  )
+  (drop
+   (ref.null ${i32_f32_f64})
+  )
+  (drop
+   (block $block (result (ref null ${i32_f32_f64}))
+    (local.get $x)
+   )
+  )
+  (drop
+   (if (result (ref null ${i32_f32_f64}))
+    (i32.const 1)
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+  (drop
+   (loop $loop-in (result (ref null ${i32_f32_f64}))
+    (local.get $x)
+   )
+  )
+  (drop
+   (select (result (ref null ${i32_f32_f64}))
+    (local.get $x)
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (struct.set ${i32_f32_f64} 0
+   (local.get $x)
+   (i32.const 100)
+  )
+  (drop
+   (struct.new_default_with_rtt ${i32_f32_f64}
+    (rtt.canon ${i32_f32_f64})
+   )
+  )
+  (drop
+   (struct.new_with_rtt ${i32_f32_f64}
+    (rtt.canon ${i32_f32_f64})
+    (i32.const 1)
+    (f32.const 2.3450000286102295)
+    (f64.const 3.14159)
+   )
+  )
+  (unreachable)
+ )
+ (func $arrays (param $x (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|]))
+  (local $tv (ref null $[mut:f64]))
+  (local $tm (ref null $[ref?|[mut:f64]|]))
+  (local $tb (ref null $[mut:i8]))
+  (local $tw (ref null $[mut:i32]))
+  (drop
+   (array.new_with_rtt $[mut:f64]
+    (rtt.canon $[mut:f64])
+    (i32.const 3)
+    (f64.const 3.14159)
+   )
+  )
+  (drop
+   (array.new_default_with_rtt $[ref?|[mut:f64]|]
+    (rtt.canon $[ref?|[mut:f64]|])
+    (i32.const 10)
+   )
+  )
+  (drop
+   (array.get $[mut:f64]
+    (local.get $x)
+    (i32.const 2)
+   )
+  )
+  (array.set $[mut:f64]
+   (local.get $x)
+   (i32.const 2)
+   (f64.const 2.18281828)
+  )
+  (drop
+   (array.len $[mut:f64]
+    (local.get $x)
+   )
+  )
+  (drop
+   (array.get $[mut:i32]
+    (local.get $tw)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (array.get_u $[mut:i8]
+    (local.get $tb)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (array.get_s $[mut:i8]
+    (local.get $tb)
+    (i32.const 3)
+   )
+  )
+  (unreachable)
+ )
+ (func $rtt-param-with-depth (param $rtt (rtt 1 ${}))
+  (nop)
+ )
+ (func $rtt-param-without-depth (param $rtt (rtt ${}))
+  (nop)
+ )
+ (func $rtt-operations
+  (local $temp.A (ref null ${i32_f32_f64}))
+  (drop
+   (ref.test ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+    (ref.null ${i32_f32_f64})
+    (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})
+   )
+  )
+  (drop
+   (ref.cast ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+    (ref.null ${i32_f32_f64})
+    (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})
+   )
+  )
+  (drop
+   (block $out (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))
+    (local.set $temp.A
+     (br_on_cast $out ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+      (ref.null ${i32_f32_f64})
+      (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})
+     )
+    )
+    (br_on_cast $out ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+     (ref.null ${i32_f32_f64})
+     (unreachable)
+    )
+    (unreachable)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/heap-types.wast.fromBinary b/binaryen/test/heap-types.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/heap-types.wast.fromBinary
@@ -0,0 +1,196 @@
+(module
+ (type ${i32_f32_f64} (struct (field i32) (field f32) (field f64)))
+ (type $[mut:f64] (array (mut f64)))
+ (type ${} (struct ))
+ (type $none_=>_none (func))
+ (type ${i32} (struct (field i32)))
+ (type ${i32_i64} (struct (field i32) (field i64)))
+ (type ${mut:f32} (struct (field (mut f32))))
+ (type $[mut:i32] (array (mut i32)))
+ (type $[mut:i8] (array (mut i8)))
+ (type ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref null ${i32_f32_f64})) (field (mut (ref null ${i32_f32_f64})))))
+ (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64])))
+ (type $rtt_1_${}_=>_none (func (param (rtt 1 ${}))))
+ (type $rtt_${}_=>_none (func (param (rtt ${}))))
+ (type $ref?|{i32_f32_f64}|_=>_ref?|{i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}| (func (param (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))))
+ (type $ref?|[mut:f64]|_=>_ref?|[ref?|[mut:f64]|]| (func (param (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|]))))
+ (global $rttparent (rtt 0 ${}) (rtt.canon ${}))
+ (global $rttchild (rtt 1 ${i32}) (rtt.sub ${i32}
+  (global.get $rttparent)
+ ))
+ (global $rttgrandchild (rtt 2 ${i32_i64}) (rtt.sub ${i32_i64}
+  (global.get $rttchild)
+ ))
+ (func $structs (param $x (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))
+  (local $tA (ref null ${i32_f32_f64}))
+  (local $tB (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))
+  (local $tc (ref null ${mut:f32}))
+  (local $tv (ref null $[ref?|[mut:f64]|]))
+  (local $tm (ref null $[mut:f64]))
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 0
+    (local.get $x)
+   )
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 1
+    (local.get $x)
+   )
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 2
+    (local.get $x)
+   )
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 2
+    (local.get $x)
+   )
+  )
+  (drop
+   (struct.get_u ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} 0
+    (local.get $tB)
+   )
+  )
+  (drop
+   (struct.get_s ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} 0
+    (local.get $tB)
+   )
+  )
+  (drop
+   (ref.null ${i32_f32_f64})
+  )
+  (drop
+   (block $label$1 (result (ref null ${i32_f32_f64}))
+    (local.get $x)
+   )
+  )
+  (drop
+   (if (result (ref null ${i32_f32_f64}))
+    (i32.const 1)
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+  (drop
+   (loop $label$4 (result (ref null ${i32_f32_f64}))
+    (local.get $x)
+   )
+  )
+  (drop
+   (select (result (ref null ${i32_f32_f64}))
+    (local.get $x)
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (struct.set ${i32_f32_f64} 0
+   (local.get $x)
+   (i32.const 100)
+  )
+  (drop
+   (struct.new_default_with_rtt ${i32_f32_f64}
+    (rtt.canon ${i32_f32_f64})
+   )
+  )
+  (drop
+   (struct.new_with_rtt ${i32_f32_f64}
+    (rtt.canon ${i32_f32_f64})
+    (i32.const 1)
+    (f32.const 2.3450000286102295)
+    (f64.const 3.14159)
+   )
+  )
+  (unreachable)
+ )
+ (func $arrays (param $x (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|]))
+  (local $tv (ref null $[ref?|[mut:f64]|]))
+  (local $tm (ref null $[mut:i32]))
+  (local $tb (ref null $[mut:i8]))
+  (local $tw (ref null $[mut:f64]))
+  (drop
+   (array.new_with_rtt $[mut:f64]
+    (rtt.canon $[mut:f64])
+    (i32.const 3)
+    (f64.const 3.14159)
+   )
+  )
+  (drop
+   (array.new_default_with_rtt $[ref?|[mut:f64]|]
+    (rtt.canon $[ref?|[mut:f64]|])
+    (i32.const 10)
+   )
+  )
+  (drop
+   (array.get $[mut:f64]
+    (local.get $x)
+    (i32.const 2)
+   )
+  )
+  (array.set $[mut:f64]
+   (local.get $x)
+   (i32.const 2)
+   (f64.const 2.18281828)
+  )
+  (drop
+   (array.len $[mut:f64]
+    (local.get $x)
+   )
+  )
+  (drop
+   (array.get $[mut:i32]
+    (local.get $tm)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (array.get_u $[mut:i8]
+    (local.get $tb)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (array.get_s $[mut:i8]
+    (local.get $tb)
+    (i32.const 3)
+   )
+  )
+  (unreachable)
+ )
+ (func $rtt-param-with-depth (param $rtt (rtt 1 ${}))
+  (nop)
+ )
+ (func $rtt-param-without-depth (param $rtt (rtt ${}))
+  (nop)
+ )
+ (func $rtt-operations
+  (local $temp.A (ref null ${i32_f32_f64}))
+  (drop
+   (ref.test ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+    (ref.null ${i32_f32_f64})
+    (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})
+   )
+  )
+  (drop
+   (ref.cast ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+    (ref.null ${i32_f32_f64})
+    (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})
+   )
+  )
+  (drop
+   (block $label$1 (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))
+    (local.set $temp.A
+     (br_on_cast $label$1 ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+      (ref.null ${i32_f32_f64})
+      (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})
+     )
+    )
+    (unreachable)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/heap-types.wast.fromBinary.noDebugInfo b/binaryen/test/heap-types.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/heap-types.wast.fromBinary.noDebugInfo
@@ -0,0 +1,196 @@
+(module
+ (type ${i32_f32_f64} (struct (field i32) (field f32) (field f64)))
+ (type $[mut:f64] (array (mut f64)))
+ (type ${} (struct ))
+ (type $none_=>_none (func))
+ (type ${i32} (struct (field i32)))
+ (type ${i32_i64} (struct (field i32) (field i64)))
+ (type ${mut:f32} (struct (field (mut f32))))
+ (type $[mut:i32] (array (mut i32)))
+ (type $[mut:i8] (array (mut i8)))
+ (type ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref null ${i32_f32_f64})) (field (mut (ref null ${i32_f32_f64})))))
+ (type $[ref?|[mut:f64]|] (array (ref null $[mut:f64])))
+ (type $rtt_1_${}_=>_none (func (param (rtt 1 ${}))))
+ (type $rtt_${}_=>_none (func (param (rtt ${}))))
+ (type $ref?|{i32_f32_f64}|_=>_ref?|{i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}| (func (param (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))))
+ (type $ref?|[mut:f64]|_=>_ref?|[ref?|[mut:f64]|]| (func (param (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|]))))
+ (global $global$0 (rtt 0 ${}) (rtt.canon ${}))
+ (global $global$1 (rtt 1 ${i32}) (rtt.sub ${i32}
+  (global.get $global$0)
+ ))
+ (global $global$2 (rtt 2 ${i32_i64}) (rtt.sub ${i32_i64}
+  (global.get $global$1)
+ ))
+ (func $0 (param $0 (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))
+  (local $1 (ref null ${i32_f32_f64}))
+  (local $2 (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))
+  (local $3 (ref null ${mut:f32}))
+  (local $4 (ref null $[ref?|[mut:f64]|]))
+  (local $5 (ref null $[mut:f64]))
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 0
+    (local.get $0)
+   )
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 1
+    (local.get $0)
+   )
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 2
+    (local.get $0)
+   )
+  )
+  (drop
+   (struct.get ${i32_f32_f64} 2
+    (local.get $0)
+   )
+  )
+  (drop
+   (struct.get_u ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} 0
+    (local.get $2)
+   )
+  )
+  (drop
+   (struct.get_s ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|} 0
+    (local.get $2)
+   )
+  )
+  (drop
+   (ref.null ${i32_f32_f64})
+  )
+  (drop
+   (block $label$1 (result (ref null ${i32_f32_f64}))
+    (local.get $0)
+   )
+  )
+  (drop
+   (if (result (ref null ${i32_f32_f64}))
+    (i32.const 1)
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (loop $label$4 (result (ref null ${i32_f32_f64}))
+    (local.get $0)
+   )
+  )
+  (drop
+   (select (result (ref null ${i32_f32_f64}))
+    (local.get $0)
+    (local.get $0)
+    (i32.const 1)
+   )
+  )
+  (struct.set ${i32_f32_f64} 0
+   (local.get $0)
+   (i32.const 100)
+  )
+  (drop
+   (struct.new_default_with_rtt ${i32_f32_f64}
+    (rtt.canon ${i32_f32_f64})
+   )
+  )
+  (drop
+   (struct.new_with_rtt ${i32_f32_f64}
+    (rtt.canon ${i32_f32_f64})
+    (i32.const 1)
+    (f32.const 2.3450000286102295)
+    (f64.const 3.14159)
+   )
+  )
+  (unreachable)
+ )
+ (func $1 (param $0 (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|]))
+  (local $1 (ref null $[ref?|[mut:f64]|]))
+  (local $2 (ref null $[mut:i32]))
+  (local $3 (ref null $[mut:i8]))
+  (local $4 (ref null $[mut:f64]))
+  (drop
+   (array.new_with_rtt $[mut:f64]
+    (rtt.canon $[mut:f64])
+    (i32.const 3)
+    (f64.const 3.14159)
+   )
+  )
+  (drop
+   (array.new_default_with_rtt $[ref?|[mut:f64]|]
+    (rtt.canon $[ref?|[mut:f64]|])
+    (i32.const 10)
+   )
+  )
+  (drop
+   (array.get $[mut:f64]
+    (local.get $0)
+    (i32.const 2)
+   )
+  )
+  (array.set $[mut:f64]
+   (local.get $0)
+   (i32.const 2)
+   (f64.const 2.18281828)
+  )
+  (drop
+   (array.len $[mut:f64]
+    (local.get $0)
+   )
+  )
+  (drop
+   (array.get $[mut:i32]
+    (local.get $2)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (array.get_u $[mut:i8]
+    (local.get $3)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (array.get_s $[mut:i8]
+    (local.get $3)
+    (i32.const 3)
+   )
+  )
+  (unreachable)
+ )
+ (func $2 (param $0 (rtt 1 ${}))
+  (nop)
+ )
+ (func $3 (param $0 (rtt ${}))
+  (nop)
+ )
+ (func $4
+  (local $0 (ref null ${i32_f32_f64}))
+  (drop
+   (ref.test ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+    (ref.null ${i32_f32_f64})
+    (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})
+   )
+  )
+  (drop
+   (ref.cast ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+    (ref.null ${i32_f32_f64})
+    (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})
+   )
+  )
+  (drop
+   (block $label$1 (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}))
+    (local.set $0
+     (br_on_cast $label$1 ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}
+      (ref.null ${i32_f32_f64})
+      (rtt.canon ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})
+     )
+    )
+    (unreachable)
+   )
+  )
+ )
+)
+
diff --git a/binaryen/test/hello_world.asm.js b/binaryen/test/hello_world.asm.js
deleted file mode 100644
--- a/binaryen/test/hello_world.asm.js
+++ /dev/null
@@ -1,10 +0,0 @@
-function () {
-  "use asm";
-  function add(x, y) {
-    x = x | 0;
-    y = y | 0;
-    return x + y | 0;
-  }
-  return { add: add };
-}
-
diff --git a/binaryen/test/i64-setTempRet0.asm.js b/binaryen/test/i64-setTempRet0.asm.js
deleted file mode 100644
--- a/binaryen/test/i64-setTempRet0.asm.js
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// Test i64 support in wasm-only builds. In this case, fastcomp emits code that is
-// not asm.js, it will only ever run as wasm, and contains special intrinsics for
-// asm2wasm that map LLVM IR into i64s.
-//
-
-function asm(global, env, buffer) {
-  "use asm";
-
-  var illegalImportResult = env.illegalImportResult;
-
-  var tempRet0 = 0; // this should be used to legalize the illegal result
-
-  function illegalResult() { // illegal result, exported
-    return i64_const(1, 2);
-  }
-
-  function imports() {
-    return i64_trunc(i64(illegalImportResult())) | 0;
-  }
-
-  return { illegalResult: illegalResult, imports: imports };
-}
-
diff --git a/binaryen/test/importedSignCast.asm.js b/binaryen/test/importedSignCast.asm.js
deleted file mode 100644
--- a/binaryen/test/importedSignCast.asm.js
+++ /dev/null
@@ -1,14 +0,0 @@
-function asm(global, env, buffer) {
-  "use asm";
-
-  var gm = env._emscripten_glIsTexture;
-
-  function func() {
-    gm(0) << 24 >> 24;
-  }
-
-  var FUNCTION_TABLE_a = [ gm ];
-
-  return { func: func };
-}
-
diff --git a/binaryen/test/imported_memory.wast.fromBinary.noDebugInfo b/binaryen/test/imported_memory.wast.fromBinary.noDebugInfo
--- a/binaryen/test/imported_memory.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/imported_memory.wast.fromBinary.noDebugInfo
@@ -1,5 +1,5 @@
 (module
  (import "env" "memory" (memory $mimport$0 256 256))
- (import "env" "table" (table $timport$1 256 256 funcref))
+ (import "env" "table" (table $timport$0 256 256 funcref))
 )
 
diff --git a/binaryen/test/imported_memory_growth.wast.fromBinary.noDebugInfo b/binaryen/test/imported_memory_growth.wast.fromBinary.noDebugInfo
--- a/binaryen/test/imported_memory_growth.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/imported_memory_growth.wast.fromBinary.noDebugInfo
@@ -1,5 +1,5 @@
 (module
  (import "env" "memory" (memory $mimport$0 256))
- (import "env" "table" (table $timport$1 256 funcref))
+ (import "env" "table" (table $timport$0 256 funcref))
 )
 
diff --git a/binaryen/test/lit/CMakeLists.txt b/binaryen/test/lit/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/CMakeLists.txt
@@ -0,0 +1,1 @@
+configure_file(lit.site.cfg.py.in lit.site.cfg.py @ONLY)
diff --git a/binaryen/test/lit/lit.cfg.py b/binaryen/test/lit/lit.cfg.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/lit.cfg.py
@@ -0,0 +1,21 @@
+import lit.formats
+
+config.name = "Binaryen lit tests"
+config.test_format = lit.formats.ShTest(True)
+
+config.suffixes = ['.wat', '.wast']
+
+config.test_source_root = os.path.dirname(__file__)
+config.test_exec_root = os.path.join(config.binaryen_build_root, 'test')
+
+# Replace all Binaryen tools with their absolute paths
+bin_dir = os.path.join(config.binaryen_build_root, 'bin')
+for tool_file in os.listdir(bin_dir):
+    tool_path = config.binaryen_build_root + '/bin/' + tool_file
+    tool = tool_file[:-4] if tool_file.endswith('.exe') else tool_file
+    config.substitutions.append((tool, tool_path))
+
+# Also make the `not` command available
+not_file = config.binaryen_src_root + '/scripts/not.py'
+python = sys.executable.replace('\\', '/')
+config.substitutions.append(('not', python + ' ' + not_file))
diff --git a/binaryen/test/lit/lit.site.cfg.py.in b/binaryen/test/lit/lit.site.cfg.py.in
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/lit.site.cfg.py.in
@@ -0,0 +1,7 @@
+import os
+
+config.binaryen_src_root = r'@CMAKE_SOURCE_DIR@'
+config.binaryen_build_root = r'@CMAKE_BINARY_DIR@'
+
+lit_config.load_config(
+    config, os.path.join(config.binaryen_src_root, 'test', 'lit', 'lit.cfg.py'))
diff --git a/binaryen/test/lit/parse-error.wast b/binaryen/test/lit/parse-error.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/parse-error.wast
@@ -0,0 +1,10 @@
+;; Test that parse errors have helpful messages
+
+;; RUN: not wasm-opt %s 2>&1 | filecheck %s
+;; CHECK: [parse exception: abc (at 8:4)]
+
+(module
+  (func $foo
+    (abc)
+  )
+)
diff --git a/binaryen/test/lit/validation/shared-memory.wast b/binaryen/test/lit/validation/shared-memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/validation/shared-memory.wast
@@ -0,0 +1,11 @@
+;; Test that shared memory requires atomics
+
+;; RUN: not wasm-opt %s 2>&1 | filecheck %s --check-prefix NO-ATOMICS
+;; RUN: wasm-opt %s --enable-threads -o - -S | filecheck %s --check-prefix ATOMICS
+
+;; NO-ATOMICS: memory is shared, but atomics are disabled
+;; ATOMICS: (memory $0 (shared 10 20))
+
+(module
+  (memory (shared 10 20))
+)
diff --git a/binaryen/test/lit/wasm-emscripten-finalize/bigint.wat b/binaryen/test/lit/wasm-emscripten-finalize/bigint.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-emscripten-finalize/bigint.wat
@@ -0,0 +1,22 @@
+;; Test that the --bigint option prevents i64s from being split up
+
+;; Run without --bigint to get a baseline
+;; RUN: wasm-emscripten-finalize %s -S | filecheck %s --check-prefix MVP
+
+;; Then run with --bigint to see the difference
+;; RUN: wasm-emscripten-finalize %s -S --bigint | filecheck %s --check-prefix BIGINT
+
+;; MVP: (export "dynCall_jj" (func $legalstub$dynCall_jj))
+;; MVP: (func $legalstub$dynCall_jj (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+
+;; BIGINT-NOT: legalstub
+;; BIGINT: (export "dynCall_jj" (func $dynCall_jj))
+;; BIGINT: (func $dynCall_jj (param $fptr i32) (param $0 i64) (result i64)
+
+(module
+ (table $0 1 1 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param i64) (result i64)
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/lit/wasm-emscripten-finalize/passive-pic.wat b/binaryen/test/lit/wasm-emscripten-finalize/passive-pic.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-emscripten-finalize/passive-pic.wat
@@ -0,0 +1,38 @@
+;; Test that wasm-emscripten-finalize can locate data within passive segments
+;; even when compiled with PIC, which means that segment addresses are non-constant.
+
+;; RUN: wasm-emscripten-finalize --enable-bulk-memory %s -o out.wasm | filecheck %s
+
+;; CHECK:  "asmConsts": {
+;; CHECK:    "3": ["hello", ["iii"], [""]]
+;; CHECK:  },
+
+(module
+ (import "env" "memory" (memory $memory 1 1))
+ (import "env" "__memory_base" (global $__memory_base i32))
+ (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32)))
+ (data passive "xxxhello\00yyy")
+ ;; memory init function similar to those generated by wasm-ld
+ (start $__wasm_init_memory)
+ (func $__wasm_init_memory
+  (memory.init 0
+   (i32.add
+    (i32.const 0)
+    (global.get $__memory_base)
+   )
+   (i32.const 0)
+   (i32.const 12)
+  )
+ )
+ ;; EM_ASM call passing string at address 3 in the passive segment
+ (func $foo (result i32)
+  (call $emscripten_asm_const_int
+   (i32.add
+    (global.get $__memory_base)
+    (i32.const 3)
+   )
+   (i32.const 0)
+   (i32.const 0)
+  )
+ )
+)
diff --git a/binaryen/test/lit/wasm-split/basic.wast b/binaryen/test/lit/wasm-split/basic.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/basic.wast
@@ -0,0 +1,141 @@
+;; RUN: wasm-split %s --export-prefix='%' -o1 %t.none.1.wasm -o2 %t.none.2.wasm -v 2>&1 \
+;; RUN:     | filecheck %s --check-prefix KEEP-NONE
+;; RUN: wasm-dis %t.none.1.wasm | filecheck %s --check-prefix KEEP-NONE-PRIMARY
+;; RUN: wasm-dis %t.none.2.wasm | filecheck %s --check-prefix KEEP-NONE-SECONDARY
+
+;; RUN: wasm-split %s --export-prefix='%' -o1 %t.foo.1.wasm -o2 %t.foo.2.wasm --keep-funcs=foo -v 2>&1 \
+;; RUN:     | filecheck %s --check-prefix KEEP-FOO
+;; RUN: wasm-dis %t.foo.1.wasm | filecheck %s --check-prefix KEEP-FOO-PRIMARY
+;; RUN: wasm-dis %t.foo.2.wasm | filecheck %s --check-prefix KEEP-FOO-SECONDARY
+
+;; RUN: wasm-split %s --export-prefix='%' -o1 %t.bar.1.wasm -o2 %t.bar.2.wasm --keep-funcs=bar -v 2>&1 \
+;; RUN:     | filecheck %s --check-prefix KEEP-BAR
+;; RUN: wasm-dis %t.bar.1.wasm | filecheck %s --check-prefix KEEP-BAR-PRIMARY
+;; RUN: wasm-dis %t.bar.2.wasm | filecheck %s --check-prefix KEEP-BAR-SECONDARY
+
+;; RUN: wasm-split %s --export-prefix='%' -o1 %t.both.1.wasm -o2 %t.both.2.wasm --keep-funcs=foo,bar -v 2>&1 \
+;; RUN:     | filecheck %s --check-prefix KEEP-BOTH
+;; RUN: wasm-dis %t.both.1.wasm | filecheck %s --check-prefix KEEP-BOTH-PRIMARY
+;; RUN: wasm-dis %t.both.2.wasm | filecheck %s --check-prefix KEEP-BOTH-SECONDARY
+
+(module
+ (table $table 1 1 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param i32) (result i32)
+  (call $bar (i32.const 0))
+ )
+ (func $bar (param i32) (result i32)
+  (call $foo (i32.const 1))
+ )
+)
+
+;; KEEP-NONE: warning: not keeping any functions in the primary module
+
+;; KEEP-NONE-PRIMARY:      (module
+;; KEEP-NONE-PRIMARY-NEXT:  (type $i32_=>_i32 (func (param i32) (result i32)))
+;; KEEP-NONE-PRIMARY-NEXT:  (import "placeholder" "0" (func $fimport$0 (param i32) (result i32)))
+;; KEEP-NONE-PRIMARY-NEXT:  (table $0 1 1 funcref)
+;; KEEP-NONE-PRIMARY-NEXT:  (elem (i32.const 0) $fimport$0)
+;; KEEP-NONE-PRIMARY-NEXT:  (export "%table" (table $0))
+;; KEEP-NONE-PRIMARY-NEXT: )
+
+;; KEEP-NONE-SECONDARY:      (module
+;; KEEP-NONE-SECONDARY-NEXT:  (type $i32_=>_i32 (func (param i32) (result i32)))
+;; KEEP-NONE-SECONDARY-NEXT:  (import "primary" "%table" (table $timport$0 1 1 funcref))
+;; KEEP-NONE-SECONDARY-NEXT:  (elem (i32.const 0) $1)
+;; KEEP-NONE-SECONDARY-NEXT:  (func $0 (param $0 i32) (result i32)
+;; KEEP-NONE-SECONDARY-NEXT:   (call $1
+;; KEEP-NONE-SECONDARY-NEXT:    (i32.const 1)
+;; KEEP-NONE-SECONDARY-NEXT:   )
+;; KEEP-NONE-SECONDARY-NEXT:  )
+;; KEEP-NONE-SECONDARY-NEXT:  (func $1 (param $0 i32) (result i32)
+;; KEEP-NONE-SECONDARY-NEXT:   (call $0
+;; KEEP-NONE-SECONDARY-NEXT:    (i32.const 0)
+;; KEEP-NONE-SECONDARY-NEXT:   )
+;; KEEP-NONE-SECONDARY-NEXT:  )
+;; KEEP-NONE-SECONDARY-NEXT: )
+
+;; KEEP-FOO: Keeping functions: foo{{$}}
+;; KEEP-FOO-NEXT: Splitting out functions: bar{{$}}
+
+;; KEEP-FOO-PRIMARY:      (module
+;; KEEP-FOO-PRIMARY-NEXT:  (type $i32_=>_i32 (func (param i32) (result i32)))
+;; KEEP-FOO-PRIMARY-NEXT:  (import "placeholder" "1" (func $fimport$0 (param i32) (result i32)))
+;; KEEP-FOO-PRIMARY-NEXT:  (table $0 2 2 funcref)
+;; KEEP-FOO-PRIMARY-NEXT:  (elem (i32.const 0) $0 $fimport$0)
+;; KEEP-FOO-PRIMARY-NEXT:  (export "%foo" (func $0))
+;; KEEP-FOO-PRIMARY-NEXT:  (export "%table" (table $0))
+;; KEEP-FOO-PRIMARY-NEXT:  (func $0 (param $0 i32) (result i32)
+;; KEEP-FOO-PRIMARY-NEXT:   (call_indirect (type $i32_=>_i32)
+;; KEEP-FOO-PRIMARY-NEXT:    (i32.const 0)
+;; KEEP-FOO-PRIMARY-NEXT:    (i32.const 1)
+;; KEEP-FOO-PRIMARY-NEXT:   )
+;; KEEP-FOO-PRIMARY-NEXT:  )
+;; KEEP-FOO-PRIMARY-NEXT: )
+
+;; KEEP-FOO-SECONDARY:      (module
+;; KEEP-FOO-SECONDARY-NEXT:  (type $i32_=>_i32 (func (param i32) (result i32)))
+;; KEEP-FOO-SECONDARY-NEXT:  (import "primary" "%table" (table $timport$0 2 2 funcref))
+;; KEEP-FOO-SECONDARY-NEXT:  (elem (i32.const 1) $0)
+;; KEEP-FOO-SECONDARY-NEXT:  (import "primary" "%foo" (func $fimport$0 (param i32) (result i32)))
+;; KEEP-FOO-SECONDARY-NEXT:  (func $0 (param $0 i32) (result i32)
+;; KEEP-FOO-SECONDARY-NEXT:   (call $fimport$0
+;; KEEP-FOO-SECONDARY-NEXT:    (i32.const 1)
+;; KEEP-FOO-SECONDARY-NEXT:   )
+;; KEEP-FOO-SECONDARY-NEXT:  )
+;; KEEP-FOO-SECONDARY-NEXT: )
+
+;; KEEP-BAR: Keeping functions: bar{{$}}
+;; KEEP-BAR-NEXT: Splitting out functions: foo{{$}}
+
+;; KEEP-BAR-PRIMARY:      (module
+;; KEEP-BAR-PRIMARY-NEXT:  (type $i32_=>_i32 (func (param i32) (result i32)))
+;; KEEP-BAR-PRIMARY-NEXT:  (import "placeholder" "0" (func $fimport$0 (param i32) (result i32)))
+;; KEEP-BAR-PRIMARY-NEXT:  (table $0 1 1 funcref)
+;; KEEP-BAR-PRIMARY-NEXT:  (elem (i32.const 0) $fimport$0)
+;; KEEP-BAR-PRIMARY-NEXT:  (export "%bar" (func $0))
+;; KEEP-BAR-PRIMARY-NEXT:  (export "%table" (table $0))
+;; KEEP-BAR-PRIMARY-NEXT:  (func $0 (param $0 i32) (result i32)
+;; KEEP-BAR-PRIMARY-NEXT:   (call_indirect (type $i32_=>_i32)
+;; KEEP-BAR-PRIMARY-NEXT:    (i32.const 1)
+;; KEEP-BAR-PRIMARY-NEXT:    (i32.const 0)
+;; KEEP-BAR-PRIMARY-NEXT:   )
+;; KEEP-BAR-PRIMARY-NEXT:  )
+;; KEEP-BAR-PRIMARY-NEXT: )
+
+;; KEEP-BAR-SECONDARY:      (module
+;; KEEP-BAR-SECONDARY-NEXT:  (type $i32_=>_i32 (func (param i32) (result i32)))
+;; KEEP-BAR-SECONDARY-NEXT:  (import "primary" "%table" (table $timport$0 1 1 funcref))
+;; KEEP-BAR-SECONDARY-NEXT:  (elem (i32.const 0) $0)
+;; KEEP-BAR-SECONDARY-NEXT:  (import "primary" "%bar" (func $fimport$0 (param i32) (result i32)))
+;; KEEP-BAR-SECONDARY-NEXT:  (func $0 (param $0 i32) (result i32)
+;; KEEP-BAR-SECONDARY-NEXT:   (call $fimport$0
+;; KEEP-BAR-SECONDARY-NEXT:    (i32.const 0)
+;; KEEP-BAR-SECONDARY-NEXT:   )
+;; KEEP-BAR-SECONDARY-NEXT:  )
+;; KEEP-BAR-SECONDARY-NEXT: )
+
+;; KEEP-BOTH: warning: not splitting any functions out to the secondary module
+;; KEEP-BOTH-NEXT: Keeping functions: bar, foo{{$}}
+;; KEEP-BOTH-NEXT: Splitting out functions:{{$}}
+
+;; KEEP-BOTH-PRIMARY:      (module
+;; KEEP-BOTH-PRIMARY-NEXT:  (type $i32_=>_i32 (func (param i32) (result i32)))
+;; KEEP-BOTH-PRIMARY-NEXT:  (table $0 1 1 funcref)
+;; KEEP-BOTH-PRIMARY-NEXT:  (elem (i32.const 0) $0)
+;; KEEP-BOTH-PRIMARY-NEXT:  (export "%table" (table $0))
+;; KEEP-BOTH-PRIMARY-NEXT:  (func $0 (param $0 i32) (result i32)
+;; KEEP-BOTH-PRIMARY-NEXT:   (call $1
+;; KEEP-BOTH-PRIMARY-NEXT:    (i32.const 0)
+;; KEEP-BOTH-PRIMARY-NEXT:   )
+;; KEEP-BOTH-PRIMARY-NEXT:  )
+;; KEEP-BOTH-PRIMARY-NEXT:  (func $1 (param $0 i32) (result i32)
+;; KEEP-BOTH-PRIMARY-NEXT:   (call $0
+;; KEEP-BOTH-PRIMARY-NEXT:    (i32.const 1)
+;; KEEP-BOTH-PRIMARY-NEXT:   )
+;; KEEP-BOTH-PRIMARY-NEXT:  )
+;; KEEP-BOTH-PRIMARY-NEXT: )
+
+;; KEEP-BOTH-SECONDARY:      (module
+;; KEEP-BOTH-SECONDARY-NEXT:  (import "primary" "%table" (table $timport$0 1 1 funcref))
+;; KEEP-BOTH-SECONDARY-NEXT: )
diff --git a/binaryen/test/lit/wasm-split/call_exports.mjs b/binaryen/test/lit/wasm-split/call_exports.mjs
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/call_exports.mjs
@@ -0,0 +1,25 @@
+// Instantiates an instrumented module, calls the given exports, then collects
+// its wasm-split profile and writes it to a given file.
+//
+// Usage:
+//
+//  node call_exports.mjs <module> <profile> <export>*
+
+import * as fs from 'fs';
+
+let wasm = process.argv[2];
+let outFile = process.argv[3];
+
+// Create the Wasm instance
+let { _, instance } = await WebAssembly.instantiate(fs.readFileSync(wasm));
+
+// Call the specified exports
+for (let i = 4; i < process.argv.length; i++) {
+  console.log('calling', process.argv[i]);
+  instance.exports[process.argv[i]]();
+}
+
+// Create and read the profile
+let profileSize = instance.exports['__write_profile'](0, 2**32 - 1);
+let profileData = Buffer.from(instance.exports.memory.buffer, 0, profileSize);
+fs.writeFileSync(outFile, profileData);
diff --git a/binaryen/test/lit/wasm-split/export-name-already-exists.wast b/binaryen/test/lit/wasm-split/export-name-already-exists.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/export-name-already-exists.wast
@@ -0,0 +1,8 @@
+;; RUN: not wasm-split %s --instrument --profile-export=foo 2>&1 \
+;; RUN:   | filecheck %s
+
+;; CHECK: error: Export foo already exists.
+
+(module
+  (export "foo" (memory 0 0))
+)
diff --git a/binaryen/test/lit/wasm-split/initial-table.wast b/binaryen/test/lit/wasm-split/initial-table.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/initial-table.wast
@@ -0,0 +1,13 @@
+;; Test that the --initial-table flag works as expected
+
+;; RUN: wasm-split %s --instrument --initial-table=1234 -S | filecheck %s
+
+;; RUN: wasm-split %s -g -o1 %t.1.wasm -o2 %t.2.wasm --initial-table=1234
+;; RUN: wasm-dis %t.1.wasm | filecheck %s
+;; RUN: wasm-dis %t.2.wasm | filecheck %s
+
+;; CHECK: (table $table 1234 funcref)
+
+(module
+ (table $table 3 funcref)
+)
diff --git a/binaryen/test/lit/wasm-split/instrument-funcs.wast b/binaryen/test/lit/wasm-split/instrument-funcs.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/instrument-funcs.wast
@@ -0,0 +1,75 @@
+;; RUN: wasm-split %s --instrument -S -o - | filecheck %s
+
+;; Check that the output round trips and validates as well
+;; RUN: wasm-split %s --instrument -g -o %t
+;; RUN: wasm-opt %t --print | filecheck %s
+
+(module
+  (import "env" "foo" (func $foo))
+  (export "bar" (func $bar))
+  (func $bar
+    (call $foo)
+  )
+  (func $baz (param i32) (result i32)
+    (local.get 0)
+  )
+)
+
+;; Check that a memory has been added
+;; CHECK: (memory $0 1 1)
+
+;; Check that the counter and timestamps have been added
+;; CHECK: (global $monotonic_counter (mut i32) (i32.const 0))
+;; CHECK: (global $bar_timestamp (mut i32) (i32.const 0))
+;; CHECK: (global $baz_timestamp (mut i32) (i32.const 0))
+
+;; And the profiling function exported
+;; CHECK: (export "__write_profile" (func $__write_profile))
+
+;; Check that the function instrumentation is correct
+
+;; CHECK:      (func $baz (param $0 i32) (result i32)
+;; CHECK-NEXT:   (if
+;; CHECK-NEXT:     (i32.eqz
+;; CHECK-NEXT:       (global.get $baz_timestamp)
+;; CHECK-NEXT:     )
+;; CHECK-NEXT:     (block
+;; CHECK-NEXT:       (global.set $monotonic_counter
+;; CHECK-NEXT:         (i32.add
+;; CHECK-NEXT:           (global.get $monotonic_counter)
+;; CHECK-NEXT:           (i32.const 1)
+;; CHECK-NEXT:         )
+;; CHECK-NEXT:       )
+;; CHECK-NEXT:       (global.set $baz_timestamp
+;; CHECK-NEXT:         (global.get $monotonic_counter)
+;; CHECK-NEXT:       )
+;; CHECK-NEXT:     )
+;; CHECK-NEXT:   )
+;; CHECK-NEXT:   (local.get $0)
+;; CHECK-NEXT: )
+
+;; Check that the profiling function is correct.
+
+;; CHECK:      (func $__write_profile (param $addr i32) (param $size i32) (result i32)
+;; CHECK-NEXT:   (if
+;; CHECK-NEXT:     (i32.ge_u
+;; CHECK-NEXT:       (local.get $size)
+;; CHECK-NEXT:       (i32.const 16)
+;; CHECK-NEXT:     )
+;; CHECK-NEXT:     (block
+;; CHECK-NEXT:       (i64.store align=1
+;; CHECK-NEXT:         (local.get $addr)
+;; CHECK-NEXT:         (i64.const {{.*}})
+;; CHECK-NEXT:       )
+;; CHECK-NEXT:       (i32.store offset=8 align=1
+;; CHECK-NEXT:         (local.get $addr)
+;; CHECK-NEXT:         (global.get $bar_timestamp)
+;; CHECK-NEXT:       )
+;; CHECK-NEXT:       (i32.store offset=12 align=1
+;; CHECK-NEXT:         (local.get $addr)
+;; CHECK-NEXT:         (global.get $baz_timestamp)
+;; CHECK-NEXT:       )
+;; CHECK-NEXT:     )
+;; CHECK-NEXT:   )
+;; CHECK-NEXT:   (i32.const 16)
+;; CHECK-NEXT: )
diff --git a/binaryen/test/lit/wasm-split/instrument-memory-too-small.wast b/binaryen/test/lit/wasm-split/instrument-memory-too-small.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/instrument-memory-too-small.wast
@@ -0,0 +1,10 @@
+;; Test that the instrumentation increases the memory bounds if necessary
+
+;; RUN: wasm-split %s --instrument -S -o - | filecheck %s
+
+;; CHECK: (memory $0 1 1)
+;; CHECK: (export "__write_profile" (func $__write_profile))
+
+(module
+  (memory $0 0 0)
+)
diff --git a/binaryen/test/lit/wasm-split/invalid-options.wast b/binaryen/test/lit/wasm-split/invalid-options.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/invalid-options.wast
@@ -0,0 +1,64 @@
+;; Test that invalid command line option combinations are properly rejected with
+;; helpful error messages.
+
+;; --instrument cannot be used with --profile
+;; RUN: not wasm-split %s --instrument --profile %t 2>&1 \
+;; RUN:   | filecheck %s --check-prefix INSTRUMENT-PROFILE
+
+;; --instrument cannot be used with -o1
+;; RUN: not wasm-split %s --instrument -o1 %t 2>&1 \
+;; RUN:   | filecheck %s --check-prefix INSTRUMENT-OUT1
+
+;; --instrument cannot be used with -o2
+;; RUN: not wasm-split %s --instrument -o2 %t 2>&1 \
+;; RUN:   | filecheck %s --check-prefix INSTRUMENT-OUT2
+
+;; --instrument cannot be used with --import-namespace
+;; RUN: not wasm-split %s --instrument --import-namespace=foo 2>&1 \
+;; RUN:   | filecheck %s --check-prefix INSTRUMENT-IMPORT-NS
+
+;; --instrument cannot be used with --placeholder-namespace
+;; RUN: not wasm-split %s --instrument --placeholder-namespace=foo 2>&1 \
+;; RUN:   | filecheck %s --check-prefix INSTRUMENT-PLACEHOLDER-NS
+
+;; --instrument cannot be used with --export-prefix
+;; RUN: not wasm-split %s --instrument --export-prefix=foo 2>&1 \
+;; RUN:   | filecheck %s --check-prefix INSTRUMENT-EXPORT-PREFIX
+
+;; --instrument cannot be used with --keep-funcs
+;; RUN: not wasm-split %s --instrument --keep-funcs=foo 2>&1 \
+;; RUN:   | filecheck %s --check-prefix INSTRUMENT-KEEP-FUNCS
+
+;; --instrument cannot be used with --split-funcs
+;; RUN: not wasm-split %s --instrument --split-funcs=foo 2>&1 \
+;; RUN:   | filecheck %s --check-prefix INSTRUMENT-SPLIT-FUNCS
+
+;; Split mode requires -o1 and -o2 rather than -o
+;; RUN: not wasm-split %s -o %t 2>&1 \
+;; RUN:   | filecheck %s --check-prefix NO-INSTRUMENT-OUT
+
+;; --instrument is required to use --profile-export
+;; RUN: not wasm-split %s --profile-export=foo 2>&1 \
+;; RUN:   | filecheck %s --check-prefix NO-INSTRUMENT-PROFILE-EXPORT
+
+;; INSTRUMENT-PROFILE: error: --profile cannot be used with --instrument
+
+;; INSTRUMENT-OUT1: error: primary output cannot be used with --instrument
+
+;; INSTRUMENT-OUT2: error: secondary output cannot be used with --instrument
+
+;; INSTRUMENT-IMPORT-NS: error: --import-namespace cannot be used with --instrument
+
+;; INSTRUMENT-PLACEHOLDER-NS: error: --placeholder-namespace cannot be used with --instrument
+
+;; INSTRUMENT-EXPORT-PREFIX: error: --export-prefix cannot be used with --instrument
+
+;; INSTRUMENT-KEEP-FUNCS: error: --keep-funcs cannot be used with --instrument
+
+;; INSTRUMENT-SPLIT-FUNCS: error: --split-funcs cannot be used with --instrument
+
+;; NO-INSTRUMENT-OUT: error: must provide separate primary and secondary output with -o1 and -o2
+
+;; NO-INSTRUMENT-PROFILE-EXPORT: error: --profile-export must be used with --instrument
+
+(module)
diff --git a/binaryen/test/lit/wasm-split/mismatched-hashes.wast b/binaryen/test/lit/wasm-split/mismatched-hashes.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/mismatched-hashes.wast
@@ -0,0 +1,23 @@
+;; Check that using different inputs for the instrumentation and splitting steps
+;; results in an error.
+
+;; Instrument the module
+;; RUN: wasm-split --instrument %s -o %t.instrumented.wasm
+
+;; Generate a profile
+;; RUN: node %S/call_exports.mjs %t.instrumented.wasm %t.prof
+
+;; Attempt to split the instrumented module
+;; RUN: not wasm-split %t.instrumented.wasm --profile=%t.prof -o1 %t.1.wasm -o2 %t.2.wasm \
+;; RUN:   2>&1 | filecheck %s
+
+;; CHECK:      error: checksum in profile does not match module checksum.
+;; CHECK-SAME: The split module must be the original module that was instrumented
+;; CHECK-SAME: to generate the profile.
+
+;; Check that the matching module succeeds
+;; RUN: wasm-split %s --profile=%t.prof -o1 %t.1.wasm -o2 %t.2.wasm
+
+(module
+ (export "memory" (memory 0 0))
+)
diff --git a/binaryen/test/lit/wasm-split/name-collision.wast b/binaryen/test/lit/wasm-split/name-collision.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/name-collision.wast
@@ -0,0 +1,16 @@
+;; Regression test for a bug in which colliding internal names between
+;; non-function exports would result in the wrong import names being used in the
+;; secondary module.
+
+;; RUN: wasm-split %s -o1 %t.1.wasm -o2 %t.2.wasm
+;; RUN: wasm-dis %t.2.wasm | filecheck %s
+
+;; CHECK-NOT: (import "primary" "memory" (table
+;; CHECK: (import "primary" "table" (table
+
+(module
+ (table $collide 1 funcref)
+ (memory $collide 1 1)
+ (export "table" (table $collide))
+ (export "memory" (memory $collide))
+)
diff --git a/binaryen/test/lit/wasm-split/profile-guided.wast b/binaryen/test/lit/wasm-split/profile-guided.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/profile-guided.wast
@@ -0,0 +1,67 @@
+;; Instrument the binary
+
+;; RUN: wasm-split --instrument %s -o %t.instrumented.wasm
+
+;; Create profiles
+
+;; RUN: node %S/call_exports.mjs %t.instrumented.wasm %t.foo.prof foo
+;; RUN: node %S/call_exports.mjs %t.instrumented.wasm %t.bar.prof bar
+;; RUN: node %S/call_exports.mjs %t.instrumented.wasm %t.both.prof foo bar
+;; RUN: node %S/call_exports.mjs %t.instrumented.wasm %t.none.prof
+
+;; Create profile-guided splits
+
+;; RUN: wasm-split %s --profile=%t.foo.prof -v -o1 %t.foo.1.wasm -o2 %t.foo.2.wasm \
+;; RUN:   | filecheck %s --check-prefix FOO
+
+;; FOO: Keeping functions: deep_foo_callee, foo, foo_callee, shared_callee
+;; FOO: Splitting out functions: bar, bar_callee, uncalled
+
+;; RUN: wasm-split %s --profile=%t.bar.prof -v -o1 %t.bar.1.wasm -o2 %t.bar.2.wasm \
+;; RUN:   | filecheck %s --check-prefix BAR
+
+;; BAR: Keeping functions: bar, bar_callee, shared_callee
+;; BAR: Splitting out functions: deep_foo_callee, foo, foo_callee, uncalled
+
+;; RUN: wasm-split %s --profile=%t.both.prof -v -o1 %t.both.1.wasm -o2 %t.both.2.wasm \
+;; RUN:   | filecheck %s --check-prefix BOTH
+
+;; BOTH: Keeping functions: bar, bar_callee, deep_foo_callee, foo, foo_callee, shared_callee
+;; BOTH: Splitting out functions: uncalled
+
+;; RUN: wasm-split %s --profile=%t.none.prof -v -o1 %t.none.1.wasm -o2 %t.none.2.wasm \
+;; RUN:   | filecheck %s --check-prefix NONE
+
+;; NONE: Keeping functions:
+;; NONE: Splitting out functions: bar, bar_callee, deep_foo_callee, foo, foo_callee, shared_callee, uncalled
+
+
+(module
+  (memory $mem 1 1)
+  (export "memory" (memory $mem))
+  (export "foo" (func $foo))
+  (export "bar" (func $bar))
+  (export "uncalled" (func $uncalled))
+
+  (func $foo
+    (call $foo_callee)
+    (call $shared_callee)
+  )
+
+  (func $bar
+    (call $shared_callee)
+    (call $bar_callee)
+  )
+
+  (func $uncalled)
+
+  (func $foo_callee
+    (call $deep_foo_callee)
+  )
+
+  (func $bar_callee)
+
+  (func $shared_callee)
+
+  (func $deep_foo_callee)
+)
diff --git a/binaryen/test/lit/wasm-split/verbose.wast b/binaryen/test/lit/wasm-split/verbose.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lit/wasm-split/verbose.wast
@@ -0,0 +1,14 @@
+;; Test that --verbose mode correctly prints the kept and split funcs
+
+;; RUN: wasm-split %s --keep-funcs=foo,bar --split-funcs=baz --verbose \
+;; RUN:   -o1 %t1.wasm -o2 %t2.wasm | filecheck %s
+
+;; CHECK: Keeping functions: bar, foo{{$}}
+;; CHECK: Splitting out functions: baz, quux{{$}}
+
+(module
+  (func $foo)
+  (func $bar)
+  (func $baz)
+  (func $quux)
+)
diff --git a/binaryen/test/lld/basic_safe_stack.wat b/binaryen/test/lld/basic_safe_stack.wat
--- a/binaryen/test/lld/basic_safe_stack.wat
+++ b/binaryen/test/lld/basic_safe_stack.wat
@@ -5,13 +5,11 @@
  (memory $0 2)
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66112))
- (global $global$1 i32 (i32.const 568))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "stackRestore" (func $stackRestore))
  (export "stackAlloc" (func $stackAlloc))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
  )
  (func $stackRestore (param $0 i32)
diff --git a/binaryen/test/lld/basic_safe_stack.wat.out b/binaryen/test/lld/basic_safe_stack.wat.out
--- a/binaryen/test/lld/basic_safe_stack.wat.out
+++ b/binaryen/test/lld/basic_safe_stack.wat.out
@@ -7,7 +7,6 @@
  (memory $0 2)
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66112))
- (global $global$1 i32 (i32.const 568))
  (global $__stack_base (mut i32) (i32.const 0))
  (global $__stack_limit (mut i32) (i32.const 0))
  (export "memory" (memory $0))
@@ -15,7 +14,6 @@
  (export "stackRestore" (func $stackRestore))
  (export "stackAlloc" (func $stackAlloc))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (export "__set_stack_limits" (func $__set_stack_limits))
  (func $__wasm_call_ctors
   (nop)
@@ -90,7 +88,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 0,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
@@ -108,7 +105,6 @@
     "__set_stack_limits"
   ],
   "namedGlobals": {
-    "__data_end" : "568"
   },
   "invokeFuncs": [
   ],
diff --git a/binaryen/test/lld/bigint.wat b/binaryen/test/lld/bigint.wat
deleted file mode 100644
--- a/binaryen/test/lld/bigint.wat
+++ /dev/null
@@ -1,10 +0,0 @@
-(module
- (table $0 1 1 funcref)
- (elem (i32.const 1) $foo)
- (export "__data_end" (global $global$1))
- (global $global$0 (mut i32) (i32.const 66208))
- (global $global$1 i32 (i32.const 658))
- (func $foo (param i64) (result i64)
-  (unreachable)
- )
-)
diff --git a/binaryen/test/lld/bigint.wat.out b/binaryen/test/lld/bigint.wat.out
deleted file mode 100644
--- a/binaryen/test/lld/bigint.wat.out
+++ /dev/null
@@ -1,42 +0,0 @@
-(module
- (type $i64_=>_i64 (func (param i64) (result i64)))
- (type $i32_i64_=>_i64 (func (param i32 i64) (result i64)))
- (table $0 1 1 funcref)
- (elem (i32.const 1) $foo)
- (global $global$0 (mut i32) (i32.const 66208))
- (global $global$1 i32 (i32.const 658))
- (export "__data_end" (global $global$1))
- (export "dynCall_jj" (func $dynCall_jj))
- (func $foo (param $0 i64) (result i64)
-  (unreachable)
- )
- (func $dynCall_jj (param $fptr i32) (param $0 i64) (result i64)
-  (call_indirect (type $i64_=>_i64)
-   (local.get $0)
-   (local.get $fptr)
-  )
- )
-)
-(;
---BEGIN METADATA --
-{
-  "staticBump": 90,
-  "tableSize": 1,
-  "declares": [
-  ],
-  "externs": [
-  ],
-  "exports": [
-    "dynCall_jj"
-  ],
-  "namedGlobals": {
-    "__data_end" : "658"
-  },
-  "invokeFuncs": [
-  ],
-  "mainReadsParams": 0,
-  "features": [
-  ]
-}
--- END METADATA --
-;)
diff --git a/binaryen/test/lld/duplicate_imports.wat.out b/binaryen/test/lld/duplicate_imports.wat.out
--- a/binaryen/test/lld/duplicate_imports.wat.out
+++ b/binaryen/test/lld/duplicate_imports.wat.out
@@ -4,8 +4,8 @@
  (type $none_=>_none (func))
  (type $none_=>_i32 (func (result i32)))
  (type $i32_=>_i32 (func (param i32) (result i32)))
- (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (type $i64_=>_i32 (func (param i64) (result i32)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (type $f32_f64_=>_f32 (func (param f32 f64) (result f32)))
  (type $f64_f64_=>_f32 (func (param f64 f64) (result f32)))
  (import "env" "puts" (func $puts1 (param i32) (result i32)))
@@ -67,7 +67,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 13,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
diff --git a/binaryen/test/lld/em_asm.wat b/binaryen/test/lld/em_asm.wat
--- a/binaryen/test/lld/em_asm.wat
+++ b/binaryen/test/lld/em_asm.wat
@@ -8,11 +8,9 @@
  (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00\00{ return $0 + $1; }\00ii\00{ Module.print(\"Got \" + $0); }\00i\00")
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66208))
- (global $global$1 i32 (i32.const 658))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
  )
  (func $__original_main (result i32)
diff --git a/binaryen/test/lld/em_asm.wat.mem.out b/binaryen/test/lld/em_asm.wat.mem.out
--- a/binaryen/test/lld/em_asm.wat.mem.out
+++ b/binaryen/test/lld/em_asm.wat.mem.out
@@ -7,11 +7,9 @@
  (memory $0 2)
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66208))
- (global $global$1 i32 (i32.const 658))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
   (nop)
  )
@@ -74,7 +72,6 @@
     "602": ["{ return $0 + $1; }", ["iii"], [""]],
     "625": ["{ Module.print(\"Got \" + $0); }", ["iii"], [""]]
   },
-  "staticBump": 90,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
@@ -89,7 +86,6 @@
     "main"
   ],
   "namedGlobals": {
-    "__data_end" : "658"
   },
   "invokeFuncs": [
   ],
diff --git a/binaryen/test/lld/em_asm.wat.out b/binaryen/test/lld/em_asm.wat.out
--- a/binaryen/test/lld/em_asm.wat.out
+++ b/binaryen/test/lld/em_asm.wat.out
@@ -8,11 +8,9 @@
  (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00\00{ return $0 + $1; }\00ii\00{ Module.print(\"Got \" + $0); }\00i\00")
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66208))
- (global $global$1 i32 (i32.const 658))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
   (nop)
  )
@@ -75,7 +73,6 @@
     "602": ["{ return $0 + $1; }", ["iii"], [""]],
     "625": ["{ Module.print(\"Got \" + $0); }", ["iii"], [""]]
   },
-  "staticBump": 90,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
@@ -90,7 +87,6 @@
     "main"
   ],
   "namedGlobals": {
-    "__data_end" : "658"
   },
   "invokeFuncs": [
   ],
diff --git a/binaryen/test/lld/em_asm64.cpp b/binaryen/test/lld/em_asm64.cpp
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm64.cpp
@@ -0,0 +1,8 @@
+#include <emscripten/em_asm.h>
+
+int main() {
+  EM_ASM({ Module.print("Hello world"); });
+  int x = EM_ASM_INT({ return $0 + $1; }, 13, 27);
+  EM_ASM_({ Module.print("Got " + $0); }, x);
+  return 0;
+}
diff --git a/binaryen/test/lld/em_asm64.wat b/binaryen/test/lld/em_asm64.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm64.wat
@@ -0,0 +1,68 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i64_=>_i32 (func (param i32 i64) (result i32)))
+ (type $i64_i64_i64_=>_i32 (func (param i64 i64 i64) (result i32)))
+ (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i64 i64 i64) (result i32)))
+ (memory $0 i64 2)
+ (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00\00{ return $0 + $1; }\00ii\00{ Module.print(\"Got \" + $0); }\00i\00")
+ (table $0 1 1 funcref)
+ (global $__stack_pointer (mut i64) (i64.const 66208))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (func $__wasm_call_ctors
+ )
+ (func $__original_main (result i32)
+  (local $0 i64)
+  (global.set $__stack_pointer
+   (local.tee $0
+    (i64.sub
+     (global.get $__stack_pointer)
+     (i64.const 32)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i64.const 568)
+    (i64.const 601)
+    (i64.const 0)
+   )
+  )
+  (i64.store offset=16
+   (local.get $0)
+   (i64.const 115964117005)
+  )
+  (i32.store
+   (local.get $0)
+   (call $emscripten_asm_const_int
+    (i64.const 602)
+    (i64.const 622)
+    (i64.add
+     (local.get $0)
+     (i64.const 16)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i64.const 625)
+    (i64.const 656)
+    (local.get $0)
+   )
+  )
+  (global.set $__stack_pointer
+   (i64.add
+    (local.get $0)
+    (i64.const 32)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i64) (result i32)
+  (call $__original_main)
+ )
+ ;; custom section "producers", size 112
+)
+
diff --git a/binaryen/test/lld/em_asm64.wat.out b/binaryen/test/lld/em_asm64.wat.out
new file mode 100644
--- /dev/null
+++ b/binaryen/test/lld/em_asm64.wat.out
@@ -0,0 +1,99 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_i64_=>_i32 (func (param i32 i64) (result i32)))
+ (type $i64_i64_i64_=>_i32 (func (param i64 i64 i64) (result i32)))
+ (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i64 i64 i64) (result i32)))
+ (memory $0 i64 2)
+ (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00\00{ return $0 + $1; }\00ii\00{ Module.print(\"Got \" + $0); }\00i\00")
+ (table $0 1 1 funcref)
+ (global $__stack_pointer (mut i64) (i64.const 66208))
+ (export "memory" (memory $0))
+ (export "__wasm_call_ctors" (func $__wasm_call_ctors))
+ (export "main" (func $main))
+ (func $__wasm_call_ctors
+  (nop)
+ )
+ (func $__original_main (result i32)
+  (local $0 i64)
+  (global.set $__stack_pointer
+   (local.tee $0
+    (i64.sub
+     (global.get $__stack_pointer)
+     (i64.const 32)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i64.const 568)
+    (i64.const 601)
+    (i64.const 0)
+   )
+  )
+  (i64.store offset=16
+   (local.get $0)
+   (i64.const 115964117005)
+  )
+  (i32.store
+   (local.get $0)
+   (call $emscripten_asm_const_int
+    (i64.const 602)
+    (i64.const 622)
+    (i64.add
+     (local.get $0)
+     (i64.const 16)
+    )
+   )
+  )
+  (drop
+   (call $emscripten_asm_const_int
+    (i64.const 625)
+    (i64.const 656)
+    (local.get $0)
+   )
+  )
+  (global.set $__stack_pointer
+   (i64.add
+    (local.get $0)
+    (i64.const 32)
+   )
+  )
+  (i32.const 0)
+ )
+ (func $main (param $0 i32) (param $1 i64) (result i32)
+  (call $__original_main)
+ )
+)
+(;
+--BEGIN METADATA --
+{
+  "asmConsts": {
+    "568": ["{ Module.print(\"Hello world\"); }", ["ijj"], [""]],
+    "602": ["{ return $0 + $1; }", ["ijj"], [""]],
+    "625": ["{ Module.print(\"Got \" + $0); }", ["ijj"], [""]]
+  },
+  "tableSize": 1,
+  "initializers": [
+    "__wasm_call_ctors"
+  ],
+  "declares": [
+    "emscripten_asm_const_int"
+  ],
+  "externs": [
+  ],
+  "exports": [
+    "__wasm_call_ctors",
+    "main"
+  ],
+  "namedGlobals": {
+  },
+  "invokeFuncs": [
+  ],
+  "mainReadsParams": 0,
+  "features": [
+    "--enable-memory64"
+  ]
+}
+-- END METADATA --
+;)
diff --git a/binaryen/test/lld/em_asm_O0.wat b/binaryen/test/lld/em_asm_O0.wat
--- a/binaryen/test/lld/em_asm_O0.wat
+++ b/binaryen/test/lld/em_asm_O0.wat
@@ -7,11 +7,9 @@
  (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00")
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66192))
- (global $global$1 i32 (i32.const 652))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
  )
  (func $main (param $0 i32) (param $1 i32) (result i32)
diff --git a/binaryen/test/lld/em_asm_O0.wat.out b/binaryen/test/lld/em_asm_O0.wat.out
--- a/binaryen/test/lld/em_asm_O0.wat.out
+++ b/binaryen/test/lld/em_asm_O0.wat.out
@@ -7,11 +7,9 @@
  (data (i32.const 568) "{ Module.print(\"Hello world\"); }\00{ return $0 + $1; }\00{ Module.print(\"Got \" + $0); }\00")
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66192))
- (global $global$1 i32 (i32.const 652))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
   (nop)
  )
@@ -100,7 +98,6 @@
     "601": ["{ return $0 + $1; }", ["iii"], [""]],
     "621": ["{ Module.print(\"Got \" + $0); }", ["iii"], [""]]
   },
-  "staticBump": 84,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
@@ -115,7 +112,6 @@
     "main"
   ],
   "namedGlobals": {
-    "__data_end" : "652"
   },
   "invokeFuncs": [
   ],
diff --git a/binaryen/test/lld/em_asm_main_thread.wat.out b/binaryen/test/lld/em_asm_main_thread.wat.out
--- a/binaryen/test/lld/em_asm_main_thread.wat.out
+++ b/binaryen/test/lld/em_asm_main_thread.wat.out
@@ -198,7 +198,6 @@
     "601": ["{ return $0 + $1; }", ["iii"], ["sync_on_main_thread_"]],
     "621": ["{ Module.print(\"Got \" + $0); }", ["iii"], ["sync_on_main_thread_"]]
   },
-  "staticBump": 84,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
diff --git a/binaryen/test/lld/em_asm_shared.wat b/binaryen/test/lld/em_asm_shared.wat
--- a/binaryen/test/lld/em_asm_shared.wat
+++ b/binaryen/test/lld/em_asm_shared.wat
@@ -4,14 +4,14 @@
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 0))
- (data (global.get $gimport$3) "{ Module.print(\"Hello world\"); }\00\00{ return $0 + $1; }\00ii\00{ Module.print(\"Got \" + $0); }\00i\00")
- (import "env" "__indirect_function_table" (table $timport$1 0 funcref))
- (import "env" "__stack_pointer" (global $gimport$2 (mut i32)))
- (import "env" "__memory_base" (global $gimport$3 i32))
- (import "env" "__table_base" (global $gimport$4 i32))
- (import "GOT.mem" "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE" (global $gimport$6 (mut i32)))
- (import "GOT.mem" "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE" (global $gimport$7 (mut i32)))
- (import "GOT.mem" "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE" (global $gimport$8 (mut i32)))
+ (data (global.get $gimport$1) "{ Module.print(\"Hello world\"); }\00\00{ return $0 + $1; }\00ii\00{ Module.print(\"Got \" + $0); }\00i\00")
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
+ (import "env" "__stack_pointer" (global $gimport$0 (mut i32)))
+ (import "env" "__memory_base" (global $gimport$1 i32))
+ (import "env" "__table_base" (global $gimport$2 i32))
+ (import "GOT.mem" "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE" (global $gimport$3 (mut i32)))
+ (import "GOT.mem" "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE" (global $gimport$4 (mut i32)))
+ (import "GOT.mem" "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE" (global $gimport$5 (mut i32)))
  (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32)))
  (global $global$0 i32 (i32.const 33))
  (global $global$1 i32 (i32.const 54))
@@ -30,10 +30,10 @@
  (func $__original_main (result i32)
   (local $0 i32)
   (local $1 i32)
-  (global.set $gimport$2
+  (global.set $gimport$0
    (local.tee $0
     (i32.sub
-     (global.get $gimport$2)
+     (global.get $gimport$0)
      (i32.const 32)
     )
    )
@@ -42,11 +42,11 @@
    (call $emscripten_asm_const_int
     (i32.add
      (local.tee $1
-      (global.get $gimport$3)
+      (global.get $gimport$1)
      )
      (i32.const 0)
     )
-    (global.get $gimport$6)
+    (global.get $gimport$3)
     (i32.const 0)
    )
   )
@@ -61,7 +61,7 @@
      (local.get $1)
      (i32.const 34)
     )
-    (global.get $gimport$7)
+    (global.get $gimport$4)
     (i32.add
      (local.get $0)
      (i32.const 16)
@@ -74,11 +74,11 @@
      (local.get $1)
      (i32.const 57)
     )
-    (global.get $gimport$8)
+    (global.get $gimport$5)
     (local.get $0)
    )
   )
-  (global.set $gimport$2
+  (global.set $gimport$0
    (i32.add
     (local.get $0)
     (i32.const 32)
diff --git a/binaryen/test/lld/em_asm_shared.wat.out b/binaryen/test/lld/em_asm_shared.wat.out
--- a/binaryen/test/lld/em_asm_shared.wat.out
+++ b/binaryen/test/lld/em_asm_shared.wat.out
@@ -1,32 +1,27 @@
 (module
- (type $none_=>_i32 (func (result i32)))
  (type $none_=>_none (func))
- (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 0))
- (data (global.get $gimport$3) "{ Module.print(\"Hello world\"); }\00\00{ return $0 + $1; }\00ii\00{ Module.print(\"Got \" + $0); }\00i\00")
- (import "env" "table" (table $timport$1 0 funcref))
- (import "env" "__memory_base" (global $gimport$3 i32))
- (import "env" "__table_base" (global $gimport$4 i32))
+ (data (global.get $gimport$1) "{ Module.print(\"Hello world\"); }\00\00{ return $0 + $1; }\00ii\00{ Module.print(\"Got \" + $0); }\00i\00")
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
+ (import "env" "__stack_pointer" (global $gimport$0 (mut i32)))
+ (import "env" "__memory_base" (global $gimport$1 i32))
+ (import "env" "__table_base" (global $gimport$2 i32))
+ (import "GOT.mem" "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE" (global $gimport$3 (mut i32)))
+ (import "GOT.mem" "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE" (global $gimport$4 (mut i32)))
+ (import "GOT.mem" "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE" (global $gimport$5 (mut i32)))
  (import "env" "emscripten_asm_const_int" (func $emscripten_asm_const_int (param i32 i32 i32) (result i32)))
- (import "env" "stackSave" (func $stackSave (result i32)))
- (import "env" "stackRestore" (func $stackRestore (param i32)))
- (import "env" "g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE" (func $g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE (result i32)))
- (import "env" "g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE" (func $g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE (result i32)))
- (import "env" "g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE" (func $g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE (result i32)))
- (global $gimport$6 (mut i32) (i32.const 0))
- (global $gimport$7 (mut i32) (i32.const 0))
- (global $gimport$8 (mut i32) (i32.const 0))
  (global $global$0 i32 (i32.const 33))
  (global $global$1 i32 (i32.const 54))
  (global $global$2 i32 (i32.const 88))
+ (export "__post_instantiate" (func $__wasm_call_ctors))
  (export "__original_main" (func $__original_main))
  (export "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE" (global $global$0))
  (export "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE" (global $global$1))
  (export "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE" (global $global$2))
  (export "main" (func $main))
- (export "__post_instantiate" (func $__post_instantiate))
  (func $__wasm_call_ctors
   (call $__wasm_apply_relocs)
  )
@@ -36,10 +31,10 @@
  (func $__original_main (result i32)
   (local $0 i32)
   (local $1 i32)
-  (call $stackRestore
+  (global.set $gimport$0
    (local.tee $0
     (i32.sub
-     (call $stackSave)
+     (global.get $gimport$0)
      (i32.const 32)
     )
    )
@@ -48,11 +43,11 @@
    (call $emscripten_asm_const_int
     (i32.add
      (local.tee $1
-      (global.get $gimport$3)
+      (global.get $gimport$1)
      )
      (i32.const 0)
     )
-    (global.get $gimport$6)
+    (global.get $gimport$3)
     (i32.const 0)
    )
   )
@@ -67,7 +62,7 @@
      (local.get $1)
      (i32.const 34)
     )
-    (global.get $gimport$7)
+    (global.get $gimport$4)
     (i32.add
      (local.get $0)
      (i32.const 16)
@@ -80,11 +75,11 @@
      (local.get $1)
      (i32.const 57)
     )
-    (global.get $gimport$8)
+    (global.get $gimport$5)
     (local.get $0)
    )
   )
-  (call $stackRestore
+  (global.set $gimport$0
    (i32.add
     (local.get $0)
     (i32.const 32)
@@ -95,21 +90,6 @@
  (func $main (param $0 i32) (param $1 i32) (result i32)
   (call $__original_main)
  )
- (func $__assign_got_enties
-  (global.set $gimport$6
-   (call $g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE)
-  )
-  (global.set $gimport$7
-   (call $g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE)
-  )
-  (global.set $gimport$8
-   (call $g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE)
-  )
- )
- (func $__post_instantiate
-  (call $__assign_got_enties)
-  (call $__wasm_call_ctors)
- )
 )
 (;
 --BEGIN METADATA --
@@ -119,24 +99,22 @@
     "34": ["{ return $0 + $1; }", ["iii"], [""]],
     "57": ["{ Module.print(\"Got \" + $0); }", ["iii"], [""]]
   },
-  "staticBump": 0,
   "tableSize": 0,
   "declares": [
-    "emscripten_asm_const_int",
-    "stackSave",
-    "stackRestore",
-    "g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE",
-    "g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE",
-    "g$_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE"
+    "emscripten_asm_const_int"
   ],
   "externs": [
+    "___stack_pointer",
     "___memory_base",
-    "___table_base"
+    "___table_base",
+    "__ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE",
+    "__ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiiEEE6bufferE",
+    "__ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJiEEE6bufferE"
   ],
   "exports": [
+    "__post_instantiate",
     "__original_main",
-    "main",
-    "__post_instantiate"
+    "main"
   ],
   "namedGlobals": {
     "_ZN20__em_asm_sig_builderI19__em_asm_type_tupleIJEEE6bufferE" : "33",
diff --git a/binaryen/test/lld/em_asm_table.wat.out b/binaryen/test/lld/em_asm_table.wat.out
--- a/binaryen/test/lld/em_asm_table.wat.out
+++ b/binaryen/test/lld/em_asm_table.wat.out
@@ -32,7 +32,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 480,
   "tableSize": 159609,
   "declares": [
     "emscripten_log",
diff --git a/binaryen/test/lld/em_js_O0.wat.out b/binaryen/test/lld/em_js_O0.wat.out
--- a/binaryen/test/lld/em_js_O0.wat.out
+++ b/binaryen/test/lld/em_js_O0.wat.out
@@ -15,7 +15,6 @@
   "emJsFuncs": {
     "noarg": "(void)<::>{ out(\"no args works\"); }"
   },
-  "staticBump": 6664,
   "tableSize": 0,
   "declares": [
   ],
diff --git a/binaryen/test/lld/gdollar_mainmodule.wat b/binaryen/test/lld/gdollar_mainmodule.wat
deleted file mode 100644
--- a/binaryen/test/lld/gdollar_mainmodule.wat
+++ /dev/null
@@ -1,20 +0,0 @@
-(module
- (import "env" "memory" (memory $0 0))
- (data (global.get $gimport$3) "")
- (import "env" "__indirect_function_table" (table $timport$1 0 funcref))
- (import "env" "__stack_pointer" (global $gimport$2 (mut i32)))
- (import "env" "__memory_base" (global $gimport$3 i32))
- (import "env" "__table_base" (global $gimport$4 i32))
- (import "GOT.mem" "someglobal1" (global $gimport$6 (mut i32)))
- (import "GOT.mem" "someglobal2" (global $gimport$7 (mut i32)))
- (import "GOT.mem" "someglobal3" (global $gimport$8 (mut i32)))
- (global $global$1 i32 (i32.const 54))
- (global $global$2 i32 (i32.const 0))
- (export "someglobal2" (global $global$1))
- (export "main" (func $main))
- (export "__data_end" (global $global$2))
- (func $main (param $0 i32) (param $1 i32) (result i32)
-  (i32.const 0)
- )
-)
-
diff --git a/binaryen/test/lld/gdollar_mainmodule.wat.out b/binaryen/test/lld/gdollar_mainmodule.wat.out
deleted file mode 100644
--- a/binaryen/test/lld/gdollar_mainmodule.wat.out
+++ /dev/null
@@ -1,73 +0,0 @@
-(module
- (type $none_=>_i32 (func (result i32)))
- (type $none_=>_none (func))
- (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
- (import "env" "memory" (memory $0 0))
- (data (global.get $gimport$3) "")
- (import "env" "table" (table $timport$1 0 funcref))
- (import "env" "__stack_pointer" (global $gimport$2_import i32))
- (import "env" "__memory_base" (global $gimport$3 i32))
- (import "env" "__table_base" (global $gimport$4 i32))
- (import "env" "g$someglobal1" (func $g$someglobal1 (result i32)))
- (import "env" "g$someglobal3" (func $g$someglobal3 (result i32)))
- (global $gimport$6 (mut i32) (i32.const 0))
- (global $gimport$7 (mut i32) (i32.const 0))
- (global $gimport$8 (mut i32) (i32.const 0))
- (global $global$1 i32 (i32.const 54))
- (global $global$2 i32 (i32.const 0))
- (global $gimport$2 (mut i32) (global.get $gimport$2_import))
- (export "someglobal2" (global $global$1))
- (export "main" (func $main))
- (export "__data_end" (global $global$2))
- (export "__assign_got_enties" (func $__assign_got_enties))
- (func $main (param $0 i32) (param $1 i32) (result i32)
-  (i32.const 0)
- )
- (func $__assign_got_enties
-  (global.set $gimport$6
-   (call $g$someglobal1)
-  )
-  (global.set $gimport$7
-   (i32.add
-    (global.get $gimport$3)
-    (global.get $global$1)
-   )
-  )
-  (global.set $gimport$8
-   (call $g$someglobal3)
-  )
- )
-)
-(;
---BEGIN METADATA --
-{
-  "staticBump": 4294966728,
-  "tableSize": 0,
-  "initializers": [
-    "__assign_got_enties"
-  ],
-  "declares": [
-    "g$someglobal1",
-    "g$someglobal3"
-  ],
-  "externs": [
-    "___stack_pointer",
-    "___memory_base",
-    "___table_base"
-  ],
-  "exports": [
-    "main",
-    "__assign_got_enties"
-  ],
-  "namedGlobals": {
-    "someglobal2" : "54",
-    "__data_end" : "0"
-  },
-  "invokeFuncs": [
-  ],
-  "mainReadsParams": 1,
-  "features": [
-  ]
-}
--- END METADATA --
-;)
diff --git a/binaryen/test/lld/hello_world.passive.wat.out b/binaryen/test/lld/hello_world.passive.wat.out
--- a/binaryen/test/lld/hello_world.passive.wat.out
+++ b/binaryen/test/lld/hello_world.passive.wat.out
@@ -40,7 +40,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 13,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
diff --git a/binaryen/test/lld/hello_world.wat b/binaryen/test/lld/hello_world.wat
--- a/binaryen/test/lld/hello_world.wat
+++ b/binaryen/test/lld/hello_world.wat
@@ -8,11 +8,9 @@
  (data (i32.const 568) "Hello, world\00")
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66128))
- (global $global$1 i32 (i32.const 581))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
  )
  (func $__original_main (result i32)
diff --git a/binaryen/test/lld/hello_world.wat.mem.out b/binaryen/test/lld/hello_world.wat.mem.out
--- a/binaryen/test/lld/hello_world.wat.mem.out
+++ b/binaryen/test/lld/hello_world.wat.mem.out
@@ -7,11 +7,9 @@
  (memory $0 2)
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66128))
- (global $global$1 i32 (i32.const 581))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
   (nop)
  )
@@ -30,7 +28,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 13,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
@@ -45,7 +42,6 @@
     "main"
   ],
   "namedGlobals": {
-    "__data_end" : "581"
   },
   "invokeFuncs": [
   ],
diff --git a/binaryen/test/lld/hello_world.wat.out b/binaryen/test/lld/hello_world.wat.out
--- a/binaryen/test/lld/hello_world.wat.out
+++ b/binaryen/test/lld/hello_world.wat.out
@@ -8,11 +8,9 @@
  (data (i32.const 568) "Hello, world\00")
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66128))
- (global $global$1 i32 (i32.const 581))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
   (nop)
  )
@@ -31,7 +29,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 13,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
@@ -46,7 +43,6 @@
     "main"
   ],
   "namedGlobals": {
-    "__data_end" : "581"
   },
   "invokeFuncs": [
   ],
diff --git a/binaryen/test/lld/init.wat b/binaryen/test/lld/init.wat
--- a/binaryen/test/lld/init.wat
+++ b/binaryen/test/lld/init.wat
@@ -5,11 +5,9 @@
  (memory $0 2)
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66112))
- (global $global$1 i32 (i32.const 576))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
   (call $init_x)
   (call $init_y)
diff --git a/binaryen/test/lld/init.wat.out b/binaryen/test/lld/init.wat.out
--- a/binaryen/test/lld/init.wat.out
+++ b/binaryen/test/lld/init.wat.out
@@ -5,11 +5,9 @@
  (memory $0 2)
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66112))
- (global $global$1 i32 (i32.const 576))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
   (call $init_x)
   (call $init_y)
@@ -43,7 +41,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 8,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
@@ -57,7 +54,6 @@
     "main"
   ],
   "namedGlobals": {
-    "__data_end" : "576"
   },
   "invokeFuncs": [
   ],
diff --git a/binaryen/test/lld/longjmp.wat b/binaryen/test/lld/longjmp.wat
--- a/binaryen/test/lld/longjmp.wat
+++ b/binaryen/test/lld/longjmp.wat
@@ -20,11 +20,9 @@
  (table $0 2 2 funcref)
  (elem (i32.const 1) $fimport$3)
  (global $global$0 (mut i32) (i32.const 66112))
- (global $global$1 i32 (i32.const 576))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $0))
  (export "main" (func $2))
- (export "__data_end" (global $global$1))
  (func $0
  )
  (func $1 (result i32)
diff --git a/binaryen/test/lld/longjmp.wat.out b/binaryen/test/lld/longjmp.wat.out
--- a/binaryen/test/lld/longjmp.wat.out
+++ b/binaryen/test/lld/longjmp.wat.out
@@ -20,11 +20,9 @@
  (table $0 2 2 funcref)
  (elem (i32.const 1) $fimport$3)
  (global $global$0 (mut i32) (i32.const 66112))
- (global $global$1 i32 (i32.const 576))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $0))
  (export "main" (func $2))
- (export "__data_end" (global $global$1))
  (export "dynCall_vii" (func $dynCall_vii))
  (func $0
   (nop)
@@ -143,7 +141,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 8,
   "tableSize": 2,
   "initializers": [
     "__wasm_call_ctors"
@@ -165,7 +162,6 @@
     "dynCall_vii"
   ],
   "namedGlobals": {
-    "__data_end" : "576"
   },
   "invokeFuncs": [
     "invoke_vii"
diff --git a/binaryen/test/lld/main_module.wat.out b/binaryen/test/lld/main_module.wat.out
--- a/binaryen/test/lld/main_module.wat.out
+++ b/binaryen/test/lld/main_module.wat.out
@@ -1,31 +1,25 @@
 (module
- (type $none_=>_i32 (func (result i32)))
  (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (import "env" "memory" (memory $0 0))
  (data (global.get $gimport$2) "Hello, world\00\00\00\00\00\00\00\00\00\00\00\00")
- (import "env" "table" (table $timport$1 1 funcref))
- (elem (global.get $gimport$3) $print_message\28\29)
- (import "env" "__stack_pointer" (global $sp_import i32))
+ (import "env" "__indirect_function_table" (table $timport$1 0 funcref))
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
  (import "env" "__memory_base" (global $gimport$2 i32))
  (import "env" "__table_base" (global $gimport$3 i32))
+ (import "GOT.mem" "external_var" (global $gimport$5 (mut i32)))
+ (import "GOT.func" "puts" (global $gimport$6 (mut i32)))
+ (import "GOT.func" "_Z13print_messagev" (global $gimport$7 (mut i32)))
  (import "env" "puts" (func $puts (param i32) (result i32)))
- (import "env" "g$external_var" (func $g$external_var (result i32)))
- (import "env" "fp$puts$ii" (func $fp$puts$ii (result i32)))
- (global $gimport$5 (mut i32) (i32.const 0))
- (global $gimport$6 (mut i32) (i32.const 0))
- (global $gimport$7 (mut i32) (i32.const 0))
  (global $global$0 i32 (i32.const 16))
  (global $global$1 i32 (i32.const 20))
  (global $global i32 (i32.const 42))
- (global $sp (mut i32) (global.get $sp_import))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "_Z13print_messagev" (func $print_message\28\29))
  (export "ptr_puts" (global $global$0))
  (export "ptr_local_func" (global $global$1))
  (export "__data_end" (global $global))
- (export "dynCall_i" (func $dynCall_i))
- (export "__assign_got_enties" (func $__assign_got_enties))
  (func $__wasm_call_ctors
   (call $__wasm_apply_relocs)
  )
@@ -58,50 +52,28 @@
    (global.get $gimport$5)
   )
  )
- (func $__assign_got_enties
-  (global.set $gimport$5
-   (call $g$external_var)
-  )
-  (global.set $gimport$6
-   (call $fp$puts$ii)
-  )
-  (global.set $gimport$7
-   (i32.add
-    (global.get $gimport$3)
-    (i32.const 0)
-   )
-  )
- )
- (func $dynCall_i (param $fptr i32) (result i32)
-  (call_indirect (type $none_=>_i32)
-   (local.get $fptr)
-  )
- )
 )
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 4294966770,
-  "tableSize": 1,
+  "tableSize": 0,
   "initializers": [
-    "__assign_got_enties",
     "__wasm_call_ctors"
   ],
   "declares": [
-    "puts",
-    "g$external_var",
-    "fp$puts$ii"
+    "puts"
   ],
   "externs": [
     "___stack_pointer",
     "___memory_base",
-    "___table_base"
+    "___table_base",
+    "_external_var",
+    "_puts",
+    "__Z13print_messagev"
   ],
   "exports": [
     "__wasm_call_ctors",
-    "_Z13print_messagev",
-    "dynCall_i",
-    "__assign_got_enties"
+    "_Z13print_messagev"
   ],
   "namedGlobals": {
     "ptr_puts" : "16",
diff --git a/binaryen/test/lld/main_module_table.wat.out b/binaryen/test/lld/main_module_table.wat.out
--- a/binaryen/test/lld/main_module_table.wat.out
+++ b/binaryen/test/lld/main_module_table.wat.out
@@ -1,52 +1,26 @@
 (module
  (type $none_=>_none (func))
- (type $i32_=>_none (func (param i32)))
- (import "env" "__stack_pointer" (global $sp_import i32))
- (import "env" "__table_base" (global $__table_base i32))
- (table $0 1 funcref)
- (elem (global.get $__table_base) $__stdio_write)
- (global $gimport$9 (mut i32) (i32.const 0))
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (import "GOT.func" "__stdio_write" (global $gimport$9 (mut i32)))
  (global $global i32 (i32.const 42))
- (global $sp (mut i32) (global.get $sp_import))
  (export "__stdio_write" (func $__stdio_write))
  (export "__data_end" (global $global))
- (export "dynCall_v" (func $dynCall_v))
- (export "__assign_got_enties" (func $__assign_got_enties))
  (func $__stdio_write
   (nop)
  )
- (func $__assign_got_enties
-  (global.set $gimport$9
-   (i32.add
-    (global.get $__table_base)
-    (i32.const 0)
-   )
-  )
- )
- (func $dynCall_v (param $fptr i32)
-  (call_indirect (type $none_=>_none)
-   (local.get $fptr)
-  )
- )
 )
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 4294966770,
-  "tableSize": 1,
-  "initializers": [
-    "__assign_got_enties"
-  ],
+  "tableSize": 0,
   "declares": [
   ],
   "externs": [
     "___stack_pointer",
-    "___table_base"
+    "___stdio_write"
   ],
   "exports": [
-    "__stdio_write",
-    "dynCall_v",
-    "__assign_got_enties"
+    "__stdio_write"
   ],
   "namedGlobals": {
     "__data_end" : "42"
diff --git a/binaryen/test/lld/main_module_table_2.wat.out b/binaryen/test/lld/main_module_table_2.wat.out
--- a/binaryen/test/lld/main_module_table_2.wat.out
+++ b/binaryen/test/lld/main_module_table_2.wat.out
@@ -1,52 +1,27 @@
 (module
  (type $none_=>_none (func))
- (type $i32_=>_none (func (param i32)))
- (import "env" "table" (table $timport$9 2 funcref))
- (elem (global.get $__table_base) $__stdio_write)
- (import "env" "__stack_pointer" (global $sp_import i32))
- (import "env" "__table_base" (global $__table_base i32))
- (global $gimport$9 (mut i32) (i32.const 0))
+ (import "env" "table" (table $timport$9 1 funcref))
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (import "GOT.func" "__stdio_write" (global $gimport$9 (mut i32)))
  (global $global i32 (i32.const 42))
- (global $sp (mut i32) (global.get $sp_import))
  (export "__stdio_write" (func $__stdio_write))
  (export "__data_end" (global $global))
- (export "dynCall_v" (func $dynCall_v))
- (export "__assign_got_enties" (func $__assign_got_enties))
  (func $__stdio_write
   (nop)
  )
- (func $__assign_got_enties
-  (global.set $gimport$9
-   (i32.add
-    (global.get $__table_base)
-    (i32.const 0)
-   )
-  )
- )
- (func $dynCall_v (param $fptr i32)
-  (call_indirect (type $none_=>_none)
-   (local.get $fptr)
-  )
- )
 )
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 4294966770,
-  "tableSize": 2,
-  "initializers": [
-    "__assign_got_enties"
-  ],
+  "tableSize": 1,
   "declares": [
   ],
   "externs": [
     "___stack_pointer",
-    "___table_base"
+    "___stdio_write"
   ],
   "exports": [
-    "__stdio_write",
-    "dynCall_v",
-    "__assign_got_enties"
+    "__stdio_write"
   ],
   "namedGlobals": {
     "__data_end" : "42"
diff --git a/binaryen/test/lld/main_module_table_3.wat.out b/binaryen/test/lld/main_module_table_3.wat.out
--- a/binaryen/test/lld/main_module_table_3.wat.out
+++ b/binaryen/test/lld/main_module_table_3.wat.out
@@ -1,52 +1,27 @@
 (module
  (type $none_=>_none (func))
- (type $i32_=>_none (func (param i32)))
- (import "env" "table" (table $timport$9 2 funcref))
- (elem (i32.const 0) $__stdio_write)
- (import "env" "__stack_pointer" (global $sp_import i32))
- (import "env" "__table_base" (global $__table_base i32))
- (global $gimport$9 (mut i32) (i32.const 0))
+ (import "env" "table" (table $timport$9 1 funcref))
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (import "GOT.func" "__stdio_write" (global $gimport$9 (mut i32)))
  (global $global i32 (i32.const 42))
- (global $sp (mut i32) (global.get $sp_import))
  (export "__stdio_write" (func $__stdio_write))
  (export "__data_end" (global $global))
- (export "dynCall_v" (func $dynCall_v))
- (export "__assign_got_enties" (func $__assign_got_enties))
  (func $__stdio_write
   (nop)
  )
- (func $__assign_got_enties
-  (global.set $gimport$9
-   (i32.add
-    (global.get $__table_base)
-    (i32.const 0)
-   )
-  )
- )
- (func $dynCall_v (param $fptr i32)
-  (call_indirect (type $none_=>_none)
-   (local.get $fptr)
-  )
- )
 )
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 4294966770,
-  "tableSize": 2,
-  "initializers": [
-    "__assign_got_enties"
-  ],
+  "tableSize": 1,
   "declares": [
   ],
   "externs": [
     "___stack_pointer",
-    "___table_base"
+    "___stdio_write"
   ],
   "exports": [
-    "__stdio_write",
-    "dynCall_v",
-    "__assign_got_enties"
+    "__stdio_write"
   ],
   "namedGlobals": {
     "__data_end" : "42"
diff --git a/binaryen/test/lld/main_module_table_4.wat.out b/binaryen/test/lld/main_module_table_4.wat.out
--- a/binaryen/test/lld/main_module_table_4.wat.out
+++ b/binaryen/test/lld/main_module_table_4.wat.out
@@ -1,52 +1,29 @@
 (module
  (type $none_=>_none (func))
- (type $i32_=>_none (func (param i32)))
- (import "env" "table" (table $timport$9 2 funcref))
- (elem (global.get $tb) $__stdio_write)
- (import "env" "__stack_pointer" (global $sp_import i32))
+ (import "env" "table" (table $timport$9 1 funcref))
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (import "GOT.func" "__stdio_write" (global $gimport$9 (mut i32)))
  (import "env" "__table_base" (global $tb i32))
- (global $gimport$9 (mut i32) (i32.const 0))
  (global $global i32 (i32.const 42))
- (global $sp (mut i32) (global.get $sp_import))
  (export "__stdio_write" (func $__stdio_write))
  (export "__data_end" (global $global))
- (export "dynCall_v" (func $dynCall_v))
- (export "__assign_got_enties" (func $__assign_got_enties))
  (func $__stdio_write
   (nop)
  )
- (func $__assign_got_enties
-  (global.set $gimport$9
-   (i32.add
-    (global.get $tb)
-    (i32.const 0)
-   )
-  )
- )
- (func $dynCall_v (param $fptr i32)
-  (call_indirect (type $none_=>_none)
-   (local.get $fptr)
-  )
- )
 )
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 4294966770,
-  "tableSize": 2,
-  "initializers": [
-    "__assign_got_enties"
-  ],
+  "tableSize": 1,
   "declares": [
   ],
   "externs": [
     "___stack_pointer",
+    "___stdio_write",
     "___table_base"
   ],
   "exports": [
-    "__stdio_write",
-    "dynCall_v",
-    "__assign_got_enties"
+    "__stdio_write"
   ],
   "namedGlobals": {
     "__data_end" : "42"
diff --git a/binaryen/test/lld/main_module_table_5.wat.out b/binaryen/test/lld/main_module_table_5.wat.out
--- a/binaryen/test/lld/main_module_table_5.wat.out
+++ b/binaryen/test/lld/main_module_table_5.wat.out
@@ -1,17 +1,15 @@
 (module
  (type $none_=>_none (func))
  (type $i32_=>_none (func (param i32)))
- (import "env" "table" (table $timport$9 2 funcref))
- (elem (global.get $tb) $other $stuff $__stdio_write)
- (import "env" "__stack_pointer" (global $sp_import i32))
+ (import "env" "table" (table $timport$9 1 funcref))
+ (elem (global.get $tb) $other $stuff)
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (import "GOT.func" "__stdio_write" (global $gimport$9 (mut i32)))
  (import "env" "__table_base" (global $tb i32))
- (global $gimport$9 (mut i32) (i32.const 0))
  (global $global i32 (i32.const 42))
- (global $sp (mut i32) (global.get $sp_import))
  (export "__stdio_write" (func $__stdio_write))
  (export "__data_end" (global $global))
  (export "dynCall_v" (func $dynCall_v))
- (export "__assign_got_enties" (func $__assign_got_enties))
  (func $__stdio_write
   (nop)
  )
@@ -21,14 +19,6 @@
  (func $stuff
   (nop)
  )
- (func $__assign_got_enties
-  (global.set $gimport$9
-   (i32.add
-    (global.get $tb)
-    (i32.const 2)
-   )
-  )
- )
  (func $dynCall_v (param $fptr i32)
   (call_indirect (type $none_=>_none)
    (local.get $fptr)
@@ -38,21 +28,17 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 4294966770,
-  "tableSize": 2,
-  "initializers": [
-    "__assign_got_enties"
-  ],
+  "tableSize": 1,
   "declares": [
   ],
   "externs": [
     "___stack_pointer",
+    "___stdio_write",
     "___table_base"
   ],
   "exports": [
     "__stdio_write",
-    "dynCall_v",
-    "__assign_got_enties"
+    "dynCall_v"
   ],
   "namedGlobals": {
     "__data_end" : "42"
diff --git a/binaryen/test/lld/recursive.wat b/binaryen/test/lld/recursive.wat
--- a/binaryen/test/lld/recursive.wat
+++ b/binaryen/test/lld/recursive.wat
@@ -7,11 +7,9 @@
  (data (i32.const 568) "%d:%d\n\00Result: %d\n\00")
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66128))
- (global $global$1 i32 (i32.const 587))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
  )
  (func $foo (param $0 i32) (param $1 i32) (result i32)
diff --git a/binaryen/test/lld/recursive.wat.out b/binaryen/test/lld/recursive.wat.out
--- a/binaryen/test/lld/recursive.wat.out
+++ b/binaryen/test/lld/recursive.wat.out
@@ -7,11 +7,9 @@
  (data (i32.const 568) "%d:%d\n\00Result: %d\n\00")
  (table $0 1 1 funcref)
  (global $global$0 (mut i32) (i32.const 66128))
- (global $global$1 i32 (i32.const 587))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
   (nop)
  )
@@ -88,7 +86,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 19,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
@@ -103,7 +100,6 @@
     "main"
   ],
   "namedGlobals": {
-    "__data_end" : "587"
   },
   "invokeFuncs": [
   ],
diff --git a/binaryen/test/lld/recursive_safe_stack.wat.out b/binaryen/test/lld/recursive_safe_stack.wat.out
--- a/binaryen/test/lld/recursive_safe_stack.wat.out
+++ b/binaryen/test/lld/recursive_safe_stack.wat.out
@@ -175,7 +175,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 19,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
diff --git a/binaryen/test/lld/reserved_func_ptr.wat b/binaryen/test/lld/reserved_func_ptr.wat
--- a/binaryen/test/lld/reserved_func_ptr.wat
+++ b/binaryen/test/lld/reserved_func_ptr.wat
@@ -11,11 +11,9 @@
  (table $0 3 3 funcref)
  (elem (i32.const 1) $address_taken_func\28int\2c\20int\2c\20int\29 $address_taken_func2\28int\2c\20int\2c\20int\29)
  (global $global$0 (mut i32) (i32.const 66112))
- (global $global$1 i32 (i32.const 568))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (func $__wasm_call_ctors
  )
  (func $address_taken_func\28int\2c\20int\2c\20int\29 (param $0 i32) (param $1 i32) (param $2 i32)
diff --git a/binaryen/test/lld/reserved_func_ptr.wat.out b/binaryen/test/lld/reserved_func_ptr.wat.out
--- a/binaryen/test/lld/reserved_func_ptr.wat.out
+++ b/binaryen/test/lld/reserved_func_ptr.wat.out
@@ -12,11 +12,9 @@
  (table $0 3 3 funcref)
  (elem (i32.const 1) $address_taken_func\28int\2c\20int\2c\20int\29 $address_taken_func2\28int\2c\20int\2c\20int\29)
  (global $global$0 (mut i32) (i32.const 66112))
- (global $global$1 i32 (i32.const 568))
  (export "memory" (memory $0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "main" (func $main))
- (export "__data_end" (global $global$1))
  (export "dynCall_viii" (func $dynCall_viii))
  (func $__wasm_call_ctors
   (nop)
@@ -123,7 +121,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 0,
   "tableSize": 3,
   "initializers": [
     "__wasm_call_ctors"
@@ -139,7 +136,6 @@
     "dynCall_viii"
   ],
   "namedGlobals": {
-    "__data_end" : "568"
   },
   "invokeFuncs": [
   ],
diff --git a/binaryen/test/lld/safe_stack_standalone-wasm.wat.out b/binaryen/test/lld/safe_stack_standalone-wasm.wat.out
--- a/binaryen/test/lld/safe_stack_standalone-wasm.wat.out
+++ b/binaryen/test/lld/safe_stack_standalone-wasm.wat.out
@@ -174,7 +174,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 19,
   "tableSize": 1,
   "initializers": [
     "__wasm_call_ctors"
diff --git a/binaryen/test/lld/shared.wat b/binaryen/test/lld/shared.wat
--- a/binaryen/test/lld/shared.wat
+++ b/binaryen/test/lld/shared.wat
@@ -3,13 +3,13 @@
  (type $none_=>_i32 (func (result i32)))
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 0))
- (data (global.get $gimport$2) "Hello, world\00\00\00\00\00\00\00\00\00\00\00\00")
- (import "env" "__indirect_function_table" (table $timport$1 0 funcref))
- (import "env" "__memory_base" (global $gimport$2 i32))
- (import "env" "__table_base" (global $gimport$3 i32))
- (import "GOT.mem" "external_var" (global $gimport$5 (mut i32)))
- (import "GOT.func" "puts" (global $gimport$6 (mut i32)))
- (import "GOT.func" "_Z13print_messagev" (global $gimport$7 (mut i32)))
+ (data (global.get $gimport$0) "Hello, world\00\00\00\00\00\00\00\00\00\00\00\00")
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
+ (import "env" "__memory_base" (global $gimport$0 i32))
+ (import "env" "__table_base" (global $gimport$1 i32))
+ (import "GOT.mem" "external_var" (global $gimport$2 (mut i32)))
+ (import "GOT.func" "puts" (global $gimport$3 (mut i32)))
+ (import "GOT.func" "_Z13print_messagev" (global $gimport$4 (mut i32)))
  (import "env" "puts" (func $puts (param i32) (result i32)))
  (global $global$0 i32 (i32.const 16))
  (global $global$1 i32 (i32.const 20))
@@ -23,30 +23,30 @@
  (func $__wasm_apply_relocs
   (i32.store
    (i32.add
-    (global.get $gimport$2)
+    (global.get $gimport$0)
     (i32.const 16)
    )
-   (global.get $gimport$6)
+   (global.get $gimport$3)
   )
   (i32.store
    (i32.add
-    (global.get $gimport$2)
+    (global.get $gimport$0)
     (i32.const 20)
    )
-   (global.get $gimport$7)
+   (global.get $gimport$4)
   )
  )
  (func $print_message\28\29 (result i32)
   (drop
    (call $puts
     (i32.add
-     (global.get $gimport$2)
+     (global.get $gimport$0)
      (i32.const 0)
     )
    )
   )
   (i32.load
-   (global.get $gimport$5)
+   (global.get $gimport$2)
   )
  )
  ;; dylink section
diff --git a/binaryen/test/lld/shared.wat.out b/binaryen/test/lld/shared.wat.out
--- a/binaryen/test/lld/shared.wat.out
+++ b/binaryen/test/lld/shared.wat.out
@@ -3,89 +3,70 @@
  (type $none_=>_i32 (func (result i32)))
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 0))
- (data (global.get $gimport$2) "Hello, world\00\00\00\00\00\00\00\00\00\00\00\00")
- (import "env" "table" (table $timport$1 0 funcref))
- (import "env" "__memory_base" (global $gimport$2 i32))
- (import "env" "__table_base" (global $gimport$3 i32))
+ (data (global.get $gimport$0) "Hello, world\00\00\00\00\00\00\00\00\00\00\00\00")
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
+ (import "env" "__memory_base" (global $gimport$0 i32))
+ (import "env" "__table_base" (global $gimport$1 i32))
+ (import "GOT.mem" "external_var" (global $gimport$2 (mut i32)))
+ (import "GOT.func" "puts" (global $gimport$3 (mut i32)))
+ (import "GOT.func" "_Z13print_messagev" (global $gimport$4 (mut i32)))
  (import "env" "puts" (func $puts (param i32) (result i32)))
- (import "env" "g$external_var" (func $g$external_var (result i32)))
- (import "env" "fp$puts$ii" (func $fp$puts$ii (result i32)))
- (import "env" "fp$_Z13print_messagev$i" (func $fp$_Z13print_messagev$i (result i32)))
- (global $gimport$5 (mut i32) (i32.const 0))
- (global $gimport$6 (mut i32) (i32.const 0))
- (global $gimport$7 (mut i32) (i32.const 0))
  (global $global$0 i32 (i32.const 16))
  (global $global$1 i32 (i32.const 20))
+ (export "__post_instantiate" (func $__wasm_call_ctors))
  (export "_Z13print_messagev" (func $print_message\28\29))
  (export "ptr_puts" (global $global$0))
  (export "ptr_local_func" (global $global$1))
- (export "__post_instantiate" (func $__post_instantiate))
  (func $__wasm_call_ctors
   (call $__wasm_apply_relocs)
  )
  (func $__wasm_apply_relocs
   (i32.store
    (i32.add
-    (global.get $gimport$2)
+    (global.get $gimport$0)
     (i32.const 16)
    )
-   (global.get $gimport$6)
+   (global.get $gimport$3)
   )
   (i32.store
    (i32.add
-    (global.get $gimport$2)
+    (global.get $gimport$0)
     (i32.const 20)
    )
-   (global.get $gimport$7)
+   (global.get $gimport$4)
   )
  )
  (func $print_message\28\29 (result i32)
   (drop
    (call $puts
     (i32.add
-     (global.get $gimport$2)
+     (global.get $gimport$0)
      (i32.const 0)
     )
    )
   )
   (i32.load
-   (global.get $gimport$5)
-  )
- )
- (func $__assign_got_enties
-  (global.set $gimport$5
-   (call $g$external_var)
-  )
-  (global.set $gimport$6
-   (call $fp$puts$ii)
-  )
-  (global.set $gimport$7
-   (call $fp$_Z13print_messagev$i)
+   (global.get $gimport$2)
   )
  )
- (func $__post_instantiate
-  (call $__assign_got_enties)
-  (call $__wasm_call_ctors)
- )
 )
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 0,
   "tableSize": 0,
   "declares": [
-    "puts",
-    "g$external_var",
-    "fp$puts$ii",
-    "fp$_Z13print_messagev$i"
+    "puts"
   ],
   "externs": [
     "___memory_base",
-    "___table_base"
+    "___table_base",
+    "_external_var",
+    "_puts",
+    "__Z13print_messagev"
   ],
   "exports": [
-    "_Z13print_messagev",
-    "__post_instantiate"
+    "__post_instantiate",
+    "_Z13print_messagev"
   ],
   "namedGlobals": {
     "ptr_puts" : "16",
diff --git a/binaryen/test/lld/shared_add_to_table.wasm.out b/binaryen/test/lld/shared_add_to_table.wasm.out
--- a/binaryen/test/lld/shared_add_to_table.wasm.out
+++ b/binaryen/test/lld/shared_add_to_table.wasm.out
@@ -1,31 +1,28 @@
 (module
- (type $none_=>_i32 (func (result i32)))
  (type $none_=>_none (func))
  (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_i32 (func (result i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 0))
- (data (global.get $gimport$3) "*\00\00\00")
- (import "env" "table" (table $timport$1 0 funcref))
- (import "env" "__memory_base" (global $gimport$3 i32))
- (import "env" "__table_base" (global $gimport$4 i32))
+ (data (global.get $gimport$1) "*\00\00\00")
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
+ (import "env" "__stack_pointer" (global $gimport$0 (mut i32)))
+ (import "env" "__memory_base" (global $gimport$1 i32))
+ (import "env" "__table_base" (global $gimport$2 i32))
+ (import "GOT.func" "_Z16waka_func_theirsi" (global $gimport$3 (mut i32)))
+ (import "GOT.func" "_Z14waka_func_minei" (global $gimport$4 (mut i32)))
+ (import "GOT.mem" "waka_mine" (global $gimport$5 (mut i32)))
+ (import "GOT.mem" "waka_others" (global $gimport$6 (mut i32)))
  (import "env" "_Z16waka_func_theirsi" (func $waka_func_theirs\28int\29 (param i32) (result i32)))
- (import "env" "g$waka_mine" (func $g$waka_mine (result i32)))
- (import "env" "g$waka_others" (func $g$waka_others (result i32)))
- (import "env" "fp$_Z16waka_func_theirsi$ii" (func $fp$_Z16waka_func_theirsi$ii (result i32)))
- (import "env" "fp$_Z14waka_func_minei$ii" (func $fp$_Z14waka_func_minei$ii (result i32)))
- (global $gimport$6 (mut i32) (i32.const 0))
- (global $gimport$7 (mut i32) (i32.const 0))
- (global $gimport$8 (mut i32) (i32.const 0))
- (global $gimport$9 (mut i32) (i32.const 0))
  (global $global$0 i32 (i32.const 0))
  (global $global$1 i32 (i32.const 0))
+ (export "__post_instantiate" (func $__wasm_call_ctors))
  (export "__wasm_apply_relocs" (func $__wasm_apply_relocs))
  (export "_Z14waka_func_minei" (func $waka_func_mine\28int\29))
  (export "__original_main" (func $__original_main))
  (export "waka_mine" (global $global$0))
  (export "main" (func $main))
  (export "__dso_handle" (global $global$1))
- (export "__post_instantiate" (func $__post_instantiate))
  (func $__wasm_call_ctors
   (call $__wasm_apply_relocs)
  )
@@ -41,15 +38,15 @@
   (local $0 i32)
   (local $1 i32)
   (local.set $0
-   (global.get $gimport$6)
+   (global.get $gimport$3)
   )
   (local.set $1
-   (global.get $gimport$7)
+   (global.get $gimport$4)
   )
   (i32.add
    (i32.add
     (i32.load
-     (global.get $gimport$8)
+     (global.get $gimport$5)
     )
     (i32.add
      (local.get $1)
@@ -57,31 +54,13 @@
     )
    )
    (i32.load
-    (global.get $gimport$9)
+    (global.get $gimport$6)
    )
   )
  )
  (func $main (param $0 i32) (param $1 i32) (result i32)
   (call $__original_main)
  )
- (func $__assign_got_enties
-  (global.set $gimport$8
-   (call $g$waka_mine)
-  )
-  (global.set $gimport$9
-   (call $g$waka_others)
-  )
-  (global.set $gimport$6
-   (call $fp$_Z16waka_func_theirsi$ii)
-  )
-  (global.set $gimport$7
-   (call $fp$_Z14waka_func_minei$ii)
-  )
- )
- (func $__post_instantiate
-  (call $__assign_got_enties)
-  (call $__wasm_call_ctors)
- )
  ;; dylink section
  ;;   memorysize: 4
  ;;   memoryalignment: 2
@@ -92,25 +71,25 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 0,
   "tableSize": 0,
   "declares": [
-    "_Z16waka_func_theirsi",
-    "g$waka_mine",
-    "g$waka_others",
-    "fp$_Z16waka_func_theirsi$ii",
-    "fp$_Z14waka_func_minei$ii"
+    "_Z16waka_func_theirsi"
   ],
   "externs": [
+    "___stack_pointer",
     "___memory_base",
-    "___table_base"
+    "___table_base",
+    "__Z16waka_func_theirsi",
+    "__Z14waka_func_minei",
+    "_waka_mine",
+    "_waka_others"
   ],
   "exports": [
+    "__post_instantiate",
     "__wasm_apply_relocs",
     "_Z14waka_func_minei",
     "__original_main",
-    "main",
-    "__post_instantiate"
+    "main"
   ],
   "namedGlobals": {
     "waka_mine" : "0",
diff --git a/binaryen/test/lld/shared_longjmp.wat b/binaryen/test/lld/shared_longjmp.wat
--- a/binaryen/test/lld/shared_longjmp.wat
+++ b/binaryen/test/lld/shared_longjmp.wat
@@ -8,21 +8,21 @@
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
  (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 0))
- (data (global.get $gimport$2) "\00\00\00\00\00\00\00\00")
- (import "env" "__indirect_function_table" (table $timport$1 0 funcref))
- (import "env" "__memory_base" (global $gimport$2 i32))
- (import "env" "__table_base" (global $gimport$3 i32))
- (import "GOT.mem" "__THREW__" (global $gimport$12 (mut i32)))
- (import "GOT.func" "emscripten_longjmp" (global $gimport$13 (mut i32)))
- (import "GOT.mem" "__threwValue" (global $gimport$14 (mut i32)))
- (import "env" "malloc" (func $fimport$4 (param i32) (result i32)))
- (import "env" "saveSetjmp" (func $fimport$5 (param i32 i32 i32 i32) (result i32)))
- (import "env" "getTempRet0" (func $fimport$6 (result i32)))
- (import "env" "emscripten_longjmp" (func $fimport$7 (param i32 i32)))
- (import "env" "invoke_vii" (func $fimport$8 (param i32 i32 i32)))
- (import "env" "testSetjmp" (func $fimport$9 (param i32 i32 i32) (result i32)))
- (import "env" "setTempRet0" (func $fimport$10 (param i32)))
- (import "env" "free" (func $fimport$11 (param i32)))
+ (data (global.get $gimport$0) "\00\00\00\00\00\00\00\00")
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
+ (import "env" "__memory_base" (global $gimport$0 i32))
+ (import "env" "__table_base" (global $gimport$1 i32))
+ (import "GOT.mem" "__THREW__" (global $gimport$2 (mut i32)))
+ (import "GOT.func" "emscripten_longjmp" (global $gimport$3 (mut i32)))
+ (import "GOT.mem" "__threwValue" (global $gimport$4 (mut i32)))
+ (import "env" "malloc" (func $fimport$0 (param i32) (result i32)))
+ (import "env" "saveSetjmp" (func $fimport$1 (param i32 i32 i32 i32) (result i32)))
+ (import "env" "getTempRet0" (func $fimport$2 (result i32)))
+ (import "env" "emscripten_longjmp" (func $fimport$3 (param i32 i32)))
+ (import "env" "invoke_vii" (func $fimport$4 (param i32 i32 i32)))
+ (import "env" "testSetjmp" (func $fimport$5 (param i32 i32 i32) (result i32)))
+ (import "env" "setTempRet0" (func $fimport$6 (param i32)))
+ (import "env" "free" (func $fimport$7 (param i32)))
  (global $global$0 i32 (i32.const 0))
  (global $global$1 i32 (i32.const 4))
  (export "__wasm_call_ctors" (func $0))
@@ -41,14 +41,14 @@
   (local $3 i32)
   (i32.store
    (local.tee $0
-    (call $fimport$4
+    (call $fimport$0
      (i32.const 40)
     )
    )
    (i32.const 0)
   )
   (local.set $1
-   (call $fimport$5
+   (call $fimport$1
     (local.get $0)
     (i32.const 1)
     (local.get $0)
@@ -56,7 +56,7 @@
    )
   )
   (local.set $2
-   (call $fimport$6)
+   (call $fimport$2)
   )
   (local.set $0
    (i32.const 0)
@@ -69,12 +69,12 @@
      )
      (i32.store
       (local.tee $0
-       (global.get $gimport$12)
+       (global.get $gimport$2)
       )
       (i32.const 0)
      )
-     (call $fimport$8
-      (global.get $gimport$13)
+     (call $fimport$4
+      (global.get $gimport$3)
       (local.get $0)
       (i32.const 1)
      )
@@ -88,7 +88,7 @@
       (i32.const 0)
      )
      (local.set $0
-      (global.get $gimport$14)
+      (global.get $gimport$4)
      )
      (block $label$4
       (br_if $label$4
@@ -107,7 +107,7 @@
       )
       (br_if $label$1
        (i32.eqz
-        (call $fimport$9
+        (call $fimport$5
          (i32.load
           (local.get $3)
          )
@@ -116,22 +116,22 @@
         )
        )
       )
-      (call $fimport$10
+      (call $fimport$6
        (local.get $0)
       )
      )
      (local.set $0
-      (call $fimport$6)
+      (call $fimport$2)
      )
      (br $label$3)
     )
    )
-   (call $fimport$11
+   (call $fimport$7
     (local.get $1)
    )
    (return)
   )
-  (call $fimport$7
+  (call $fimport$3
    (local.get $3)
    (local.get $0)
   )
diff --git a/binaryen/test/lld/shared_longjmp.wat.out b/binaryen/test/lld/shared_longjmp.wat.out
--- a/binaryen/test/lld/shared_longjmp.wat.out
+++ b/binaryen/test/lld/shared_longjmp.wat.out
@@ -1,38 +1,35 @@
 (module
  (type $none_=>_none (func))
- (type $none_=>_i32 (func (result i32)))
  (type $i32_=>_none (func (param i32)))
  (type $i32_i32_=>_none (func (param i32 i32)))
  (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
  (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 0))
- (data (global.get $gimport$2) "\00\00\00\00\00\00\00\00")
- (import "env" "table" (table $timport$1 0 funcref))
- (import "env" "__memory_base" (global $gimport$2 i32))
- (import "env" "__table_base" (global $gimport$3 i32))
- (import "env" "malloc" (func $fimport$4 (param i32) (result i32)))
- (import "env" "saveSetjmp" (func $fimport$5 (param i32 i32 i32 i32) (result i32)))
- (import "env" "getTempRet0" (func $fimport$6 (result i32)))
- (import "env" "emscripten_longjmp" (func $fimport$7 (param i32 i32)))
- (import "env" "invoke_vii" (func $fimport$8 (param i32 i32 i32)))
- (import "env" "testSetjmp" (func $fimport$9 (param i32 i32 i32) (result i32)))
- (import "env" "setTempRet0" (func $fimport$10 (param i32)))
- (import "env" "free" (func $fimport$11 (param i32)))
- (import "env" "g$__THREW__" (func $g$__THREW__ (result i32)))
- (import "env" "g$__threwValue" (func $g$__threwValue (result i32)))
- (import "env" "fp$emscripten_longjmp$vii" (func $fp$emscripten_longjmp$vii (result i32)))
- (global $gimport$12 (mut i32) (i32.const 0))
- (global $gimport$13 (mut i32) (i32.const 0))
- (global $gimport$14 (mut i32) (i32.const 0))
+ (data (global.get $gimport$0) "\00\00\00\00\00\00\00\00")
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
+ (import "env" "__memory_base" (global $gimport$0 i32))
+ (import "env" "__table_base" (global $gimport$1 i32))
+ (import "GOT.mem" "__THREW__" (global $gimport$2 (mut i32)))
+ (import "GOT.func" "emscripten_longjmp" (global $gimport$3 (mut i32)))
+ (import "GOT.mem" "__threwValue" (global $gimport$4 (mut i32)))
+ (import "env" "malloc" (func $fimport$0 (param i32) (result i32)))
+ (import "env" "saveSetjmp" (func $fimport$1 (param i32 i32 i32 i32) (result i32)))
+ (import "env" "getTempRet0" (func $fimport$2 (result i32)))
+ (import "env" "emscripten_longjmp" (func $fimport$3 (param i32 i32)))
+ (import "env" "invoke_vii" (func $fimport$4 (param i32 i32 i32)))
+ (import "env" "testSetjmp" (func $fimport$5 (param i32 i32 i32) (result i32)))
+ (import "env" "setTempRet0" (func $fimport$6 (param i32)))
+ (import "env" "free" (func $fimport$7 (param i32)))
  (global $global$0 i32 (i32.const 0))
  (global $global$1 i32 (i32.const 4))
+ (export "__post_instantiate" (func $0))
  (export "_start" (func $2))
  (export "__THREW__" (global $global$0))
  (export "__threwValue" (global $global$1))
  (export "dynCall_vii" (func $dynCall_vii))
- (export "__post_instantiate" (func $__post_instantiate))
  (func $0
   (call $1)
  )
@@ -46,14 +43,14 @@
   (local $3 i32)
   (i32.store
    (local.tee $0
-    (call $fimport$4
+    (call $fimport$0
      (i32.const 40)
     )
    )
    (i32.const 0)
   )
   (local.set $1
-   (call $fimport$5
+   (call $fimport$1
     (local.get $0)
     (i32.const 1)
     (local.get $0)
@@ -61,7 +58,7 @@
    )
   )
   (local.set $2
-   (call $fimport$6)
+   (call $fimport$2)
   )
   (local.set $0
    (i32.const 0)
@@ -74,12 +71,12 @@
      )
      (i32.store
       (local.tee $0
-       (global.get $gimport$12)
+       (global.get $gimport$2)
       )
       (i32.const 0)
      )
-     (call $fimport$8
-      (global.get $gimport$13)
+     (call $fimport$4
+      (global.get $gimport$3)
       (local.get $0)
       (i32.const 1)
      )
@@ -93,7 +90,7 @@
       (i32.const 0)
      )
      (local.set $0
-      (global.get $gimport$14)
+      (global.get $gimport$4)
      )
      (block $label$4
       (br_if $label$4
@@ -112,7 +109,7 @@
       )
       (br_if $label$1
        (i32.eqz
-        (call $fimport$9
+        (call $fimport$5
          (i32.load
           (local.get $3)
          )
@@ -121,38 +118,27 @@
         )
        )
       )
-      (call $fimport$10
+      (call $fimport$6
        (local.get $0)
       )
      )
      (local.set $0
-      (call $fimport$6)
+      (call $fimport$2)
      )
      (br $label$3)
     )
    )
-   (call $fimport$11
+   (call $fimport$7
     (local.get $1)
    )
    (return)
   )
-  (call $fimport$7
+  (call $fimport$3
    (local.get $3)
    (local.get $0)
   )
   (unreachable)
  )
- (func $__assign_got_enties
-  (global.set $gimport$12
-   (call $g$__THREW__)
-  )
-  (global.set $gimport$14
-   (call $g$__threwValue)
-  )
-  (global.set $gimport$13
-   (call $fp$emscripten_longjmp$vii)
-  )
- )
  (func $dynCall_vii (param $fptr i32) (param $0 i32) (param $1 i32)
   (call_indirect (type $i32_i32_=>_none)
    (local.get $0)
@@ -160,15 +146,10 @@
    (local.get $fptr)
   )
  )
- (func $__post_instantiate
-  (call $__assign_got_enties)
-  (call $0)
- )
 )
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 0,
   "tableSize": 0,
   "declares": [
     "malloc",
@@ -177,19 +158,19 @@
     "emscripten_longjmp",
     "testSetjmp",
     "setTempRet0",
-    "free",
-    "g$__THREW__",
-    "g$__threwValue",
-    "fp$emscripten_longjmp$vii"
+    "free"
   ],
   "externs": [
     "___memory_base",
-    "___table_base"
+    "___table_base",
+    "___THREW__",
+    "_emscripten_longjmp",
+    "___threwValue"
   ],
   "exports": [
+    "__post_instantiate",
     "_start",
-    "dynCall_vii",
-    "__post_instantiate"
+    "dynCall_vii"
   ],
   "namedGlobals": {
     "__THREW__" : "0",
diff --git a/binaryen/test/lld/standalone-wasm-with-start.wat.out b/binaryen/test/lld/standalone-wasm-with-start.wat.out
--- a/binaryen/test/lld/standalone-wasm-with-start.wat.out
+++ b/binaryen/test/lld/standalone-wasm-with-start.wat.out
@@ -20,7 +20,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 8,
   "tableSize": 1,
   "declares": [
   ],
diff --git a/binaryen/test/lld/standalone-wasm.wat.out b/binaryen/test/lld/standalone-wasm.wat.out
--- a/binaryen/test/lld/standalone-wasm.wat.out
+++ b/binaryen/test/lld/standalone-wasm.wat.out
@@ -24,7 +24,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 8,
   "tableSize": 1,
   "declares": [
   ],
diff --git a/binaryen/test/lld/standalone-wasm2.wat.out b/binaryen/test/lld/standalone-wasm2.wat.out
--- a/binaryen/test/lld/standalone-wasm2.wat.out
+++ b/binaryen/test/lld/standalone-wasm2.wat.out
@@ -21,7 +21,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 8,
   "tableSize": 0,
   "declares": [
   ],
diff --git a/binaryen/test/lld/standalone-wasm3.wat.out b/binaryen/test/lld/standalone-wasm3.wat.out
--- a/binaryen/test/lld/standalone-wasm3.wat.out
+++ b/binaryen/test/lld/standalone-wasm3.wat.out
@@ -14,7 +14,6 @@
 (;
 --BEGIN METADATA --
 {
-  "staticBump": 8,
   "tableSize": 0,
   "declares": [
   ],
diff --git a/binaryen/test/memorygrowth-minimal.asm.js b/binaryen/test/memorygrowth-minimal.asm.js
deleted file mode 100644
--- a/binaryen/test/memorygrowth-minimal.asm.js
+++ /dev/null
@@ -1,41 +0,0 @@
-Module["asm"] =  (function(global,env,buffer) {
-
- "almost asm";
- var a = global.Int8Array;
- var b = global.Int16Array;
- var c = global.Int32Array;
- var d = global.Uint8Array;
- var e = global.Uint16Array;
- var f = global.Uint32Array;
- var g = global.Float32Array;
- var h = global.Float64Array;
- var i = new a(buffer);
- var j = new b(buffer);
- var k = new c(buffer);
- var l = new d(buffer);
- var m = new e(buffer);
- var n = new f(buffer);
- var o = new g(buffer);
- var p = new h(buffer);
- var q = global.byteLength;
-
- function replaceBuffer(newBuffer) {
-  if (q(newBuffer) & 16777215 || q(newBuffer) <= 16777215 || q(newBuffer) > 2147483648) return false;
-  i = new a(newBuffer);
-  j = new b(newBuffer);
-  k = new c(newBuffer);
-  l = new d(newBuffer);
-  m = new e(newBuffer);
-  n = new f(newBuffer);
-  o = new g(newBuffer);
-  p = new h(newBuffer);
-  buffer = newBuffer;
-  return true;
- }
- return {
-  _emscripten_replace_memory: replaceBuffer
- };
-})
-
-
-;
diff --git a/binaryen/test/memorygrowth.asm.js b/binaryen/test/memorygrowth.asm.js
deleted file mode 100644
--- a/binaryen/test/memorygrowth.asm.js
+++ /dev/null
@@ -1,2387 +0,0 @@
-Module["asm"] =  (function(global,env,buffer) {
-
- "almost asm";
- var a = global.Int8Array;
- var b = global.Int16Array;
- var c = global.Int32Array;
- var d = global.Uint8Array;
- var e = global.Uint16Array;
- var f = global.Uint32Array;
- var g = global.Float32Array;
- var h = global.Float64Array;
- var i = new a(buffer);
- var j = new b(buffer);
- var k = new c(buffer);
- var l = new d(buffer);
- var m = new e(buffer);
- var n = new f(buffer);
- var o = new g(buffer);
- var p = new h(buffer);
- var q = global.byteLength;
- var r = env.STACKTOP | 0;
- var s = env.STACK_MAX | 0;
- var t = env.tempDoublePtr | 0;
- var u = env.ABORT | 0;
- var v = 0;
- var w = 0;
- var x = 0;
- var y = 0;
- var z = global.NaN, A = global.Infinity;
- var B = 0, C = 0, D = 0, E = 0, F = 0.0, G = 0, H = 0, I = 0, J = 0.0;
- var K = 0;
- var L = 0;
- var M = 0;
- var N = 0;
- var O = 0;
- var P = 0;
- var Q = 0;
- var R = 0;
- var S = 0;
- var T = 0;
- var U = global.Math.floor;
- var V = global.Math.abs;
- var W = global.Math.sqrt;
- var X = global.Math.pow;
- var Y = global.Math.cos;
- var Z = global.Math.sin;
- var _ = global.Math.tan;
- var $ = global.Math.acos;
- var aa = global.Math.asin;
- var ba = global.Math.atan;
- var ca = global.Math.atan2;
- var da = global.Math.exp;
- var ea = global.Math.log;
- var fa = global.Math.ceil;
- var ga = global.Math.imul;
- var ha = global.Math.min;
- var ia = global.Math.clz32;
- var ja = env.abort;
- var ka = env.assert;
- var la = env.invoke_ii;
- var ma = env.invoke_iiii;
- var na = env.invoke_vi;
- var oa = env._pthread_cleanup_pop;
- var pa = env.___lock;
- var qa = env._abort;
- var ra = env._pthread_cleanup_push;
- var sa = env.___syscall6;
- var ta = env._sbrk;
- var ua = env.___syscall140;
- var va = env._emscripten_memcpy_big;
- var wa = env.___syscall54;
- var xa = env.___unlock;
- var ya = env.___syscall146;
- var za = 0.0;
- function Aa(newBuffer) {
-  if (q(newBuffer) & 16777215 || q(newBuffer) <= 16777215 || q(newBuffer) > 2147483648) return false;
-  i = new a(newBuffer);
-  j = new b(newBuffer);
-  k = new c(newBuffer);
-  l = new d(newBuffer);
-  m = new e(newBuffer);
-  n = new f(newBuffer);
-  o = new g(newBuffer);
-  p = new h(newBuffer);
-  buffer = newBuffer;
-  return true;
- }
- 
-// EMSCRIPTEN_START_FUNCS
-
-function eb(a) {
- a = a | 0;
- var b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, i = 0, j = 0, l = 0, m = 0, n = 0, o = 0, p = 0, q = 0, s = 0, t = 0, u = 0, v = 0, w = 0, x = 0, y = 0, z = 0, A = 0, B = 0, C = 0, D = 0, E = 0, F = 0, G = 0, H = 0, I = 0, J = 0, K = 0, L = 0, M = 0, N = 0, O = 0, P = 0, Q = 0, R = 0, S = 0, T = 0, U = 0, V = 0, W = 0, X = 0, Y = 0, Z = 0, _ = 0, $ = 0, aa = 0, ba = 0, ca = 0, da = 0, ea = 0, fa = 0, ga = 0, ha = 0, ia = 0, ja = 0, ka = 0, la = 0, ma = 0, na = 0, oa = 0, pa = 0, ra = 0, sa = 0, ua = 0, va = 0, wa = 0, xa = 0, ya = 0, za = 0, Aa = 0, Ba = 0, Ca = 0, Da = 0, Ea = 0, Fa = 0, Ga = 0, Ha = 0, Ia = 0, Ja = 0, Ka = 0, La = 0, Ma = 0, Na = 0, Oa = 0, Pa = 0, Ra = 0, Sa = 0;
- b = r;
- r = r + 16 | 0;
- c = b;
- do if (a >>> 0 < 245) {
-  d = a >>> 0 < 11 ? 16 : a + 11 & -8;
-  e = d >>> 3;
-  f = k[302] | 0;
-  g = f >>> e;
-  if (g & 3 | 0) {
-   h = (g & 1 ^ 1) + e | 0;
-   i = 1248 + (h << 1 << 2) | 0;
-   j = i + 8 | 0;
-   l = k[j >> 2] | 0;
-   m = l + 8 | 0;
-   n = k[m >> 2] | 0;
-   do if ((i | 0) == (n | 0)) k[302] = f & ~(1 << h); else {
-    if (n >>> 0 < (k[306] | 0) >>> 0) qa();
-    o = n + 12 | 0;
-    if ((k[o >> 2] | 0) == (l | 0)) {
-     k[o >> 2] = i;
-     k[j >> 2] = n;
-     break;
-    } else qa();
-   } while (0);
-   n = h << 3;
-   k[l + 4 >> 2] = n | 3;
-   j = l + n + 4 | 0;
-   k[j >> 2] = k[j >> 2] | 1;
-   p = m;
-   r = b;
-   return p | 0;
-  }
-  j = k[304] | 0;
-  if (d >>> 0 > j >>> 0) {
-   if (g | 0) {
-    n = 2 << e;
-    i = g << e & (n | 0 - n);
-    n = (i & 0 - i) + -1 | 0;
-    i = n >>> 12 & 16;
-    o = n >>> i;
-    n = o >>> 5 & 8;
-    q = o >>> n;
-    o = q >>> 2 & 4;
-    s = q >>> o;
-    q = s >>> 1 & 2;
-    t = s >>> q;
-    s = t >>> 1 & 1;
-    u = (n | i | o | q | s) + (t >>> s) | 0;
-    s = 1248 + (u << 1 << 2) | 0;
-    t = s + 8 | 0;
-    q = k[t >> 2] | 0;
-    o = q + 8 | 0;
-    i = k[o >> 2] | 0;
-    do if ((s | 0) == (i | 0)) {
-     k[302] = f & ~(1 << u);
-     v = j;
-    } else {
-     if (i >>> 0 < (k[306] | 0) >>> 0) qa();
-     n = i + 12 | 0;
-     if ((k[n >> 2] | 0) == (q | 0)) {
-      k[n >> 2] = s;
-      k[t >> 2] = i;
-      v = k[304] | 0;
-      break;
-     } else qa();
-    } while (0);
-    i = (u << 3) - d | 0;
-    k[q + 4 >> 2] = d | 3;
-    t = q + d | 0;
-    k[t + 4 >> 2] = i | 1;
-    k[t + i >> 2] = i;
-    if (v | 0) {
-     s = k[307] | 0;
-     j = v >>> 3;
-     f = 1248 + (j << 1 << 2) | 0;
-     e = k[302] | 0;
-     g = 1 << j;
-     if (!(e & g)) {
-      k[302] = e | g;
-      w = f + 8 | 0;
-      x = f;
-     } else {
-      g = f + 8 | 0;
-      e = k[g >> 2] | 0;
-      if (e >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-       w = g;
-       x = e;
-      }
-     }
-     k[w >> 2] = s;
-     k[x + 12 >> 2] = s;
-     k[s + 8 >> 2] = x;
-     k[s + 12 >> 2] = f;
-    }
-    k[304] = i;
-    k[307] = t;
-    p = o;
-    r = b;
-    return p | 0;
-   }
-   t = k[303] | 0;
-   if (!t) y = d; else {
-    i = (t & 0 - t) + -1 | 0;
-    t = i >>> 12 & 16;
-    f = i >>> t;
-    i = f >>> 5 & 8;
-    s = f >>> i;
-    f = s >>> 2 & 4;
-    e = s >>> f;
-    s = e >>> 1 & 2;
-    g = e >>> s;
-    e = g >>> 1 & 1;
-    j = k[1512 + ((i | t | f | s | e) + (g >>> e) << 2) >> 2] | 0;
-    e = (k[j + 4 >> 2] & -8) - d | 0;
-    g = j;
-    s = j;
-    while (1) {
-     j = k[g + 16 >> 2] | 0;
-     if (!j) {
-      f = k[g + 20 >> 2] | 0;
-      if (!f) {
-       z = e;
-       A = s;
-       break;
-      } else B = f;
-     } else B = j;
-     j = (k[B + 4 >> 2] & -8) - d | 0;
-     f = j >>> 0 < e >>> 0;
-     e = f ? j : e;
-     g = B;
-     s = f ? B : s;
-    }
-    s = k[306] | 0;
-    if (A >>> 0 < s >>> 0) qa();
-    g = A + d | 0;
-    if (A >>> 0 >= g >>> 0) qa();
-    e = k[A + 24 >> 2] | 0;
-    o = k[A + 12 >> 2] | 0;
-    do if ((o | 0) == (A | 0)) {
-     q = A + 20 | 0;
-     u = k[q >> 2] | 0;
-     if (!u) {
-      f = A + 16 | 0;
-      j = k[f >> 2] | 0;
-      if (!j) {
-       C = 0;
-       break;
-      } else {
-       D = j;
-       E = f;
-      }
-     } else {
-      D = u;
-      E = q;
-     }
-     while (1) {
-      q = D + 20 | 0;
-      u = k[q >> 2] | 0;
-      if (u | 0) {
-       D = u;
-       E = q;
-       continue;
-      }
-      q = D + 16 | 0;
-      u = k[q >> 2] | 0;
-      if (!u) {
-       F = D;
-       G = E;
-       break;
-      } else {
-       D = u;
-       E = q;
-      }
-     }
-     if (G >>> 0 < s >>> 0) qa(); else {
-      k[G >> 2] = 0;
-      C = F;
-      break;
-     }
-    } else {
-     q = k[A + 8 >> 2] | 0;
-     if (q >>> 0 < s >>> 0) qa();
-     u = q + 12 | 0;
-     if ((k[u >> 2] | 0) != (A | 0)) qa();
-     f = o + 8 | 0;
-     if ((k[f >> 2] | 0) == (A | 0)) {
-      k[u >> 2] = o;
-      k[f >> 2] = q;
-      C = o;
-      break;
-     } else qa();
-    } while (0);
-    do if (e | 0) {
-     o = k[A + 28 >> 2] | 0;
-     s = 1512 + (o << 2) | 0;
-     if ((A | 0) == (k[s >> 2] | 0)) {
-      k[s >> 2] = C;
-      if (!C) {
-       k[303] = k[303] & ~(1 << o);
-       break;
-      }
-     } else {
-      if (e >>> 0 < (k[306] | 0) >>> 0) qa();
-      o = e + 16 | 0;
-      if ((k[o >> 2] | 0) == (A | 0)) k[o >> 2] = C; else k[e + 20 >> 2] = C;
-      if (!C) break;
-     }
-     o = k[306] | 0;
-     if (C >>> 0 < o >>> 0) qa();
-     k[C + 24 >> 2] = e;
-     s = k[A + 16 >> 2] | 0;
-     do if (s | 0) if (s >>> 0 < o >>> 0) qa(); else {
-      k[C + 16 >> 2] = s;
-      k[s + 24 >> 2] = C;
-      break;
-     } while (0);
-     s = k[A + 20 >> 2] | 0;
-     if (s | 0) if (s >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-      k[C + 20 >> 2] = s;
-      k[s + 24 >> 2] = C;
-      break;
-     }
-    } while (0);
-    if (z >>> 0 < 16) {
-     e = z + d | 0;
-     k[A + 4 >> 2] = e | 3;
-     s = A + e + 4 | 0;
-     k[s >> 2] = k[s >> 2] | 1;
-    } else {
-     k[A + 4 >> 2] = d | 3;
-     k[g + 4 >> 2] = z | 1;
-     k[g + z >> 2] = z;
-     s = k[304] | 0;
-     if (s | 0) {
-      e = k[307] | 0;
-      o = s >>> 3;
-      s = 1248 + (o << 1 << 2) | 0;
-      q = k[302] | 0;
-      f = 1 << o;
-      if (!(q & f)) {
-       k[302] = q | f;
-       H = s + 8 | 0;
-       I = s;
-      } else {
-       f = s + 8 | 0;
-       q = k[f >> 2] | 0;
-       if (q >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-        H = f;
-        I = q;
-       }
-      }
-      k[H >> 2] = e;
-      k[I + 12 >> 2] = e;
-      k[e + 8 >> 2] = I;
-      k[e + 12 >> 2] = s;
-     }
-     k[304] = z;
-     k[307] = g;
-    }
-    p = A + 8 | 0;
-    r = b;
-    return p | 0;
-   }
-  } else y = d;
- } else if (a >>> 0 > 4294967231) y = -1; else {
-  s = a + 11 | 0;
-  e = s & -8;
-  q = k[303] | 0;
-  if (!q) y = e; else {
-   f = 0 - e | 0;
-   o = s >>> 8;
-   if (!o) J = 0; else if (e >>> 0 > 16777215) J = 31; else {
-    s = (o + 1048320 | 0) >>> 16 & 8;
-    u = o << s;
-    o = (u + 520192 | 0) >>> 16 & 4;
-    j = u << o;
-    u = (j + 245760 | 0) >>> 16 & 2;
-    t = 14 - (o | s | u) + (j << u >>> 15) | 0;
-    J = e >>> (t + 7 | 0) & 1 | t << 1;
-   }
-   t = k[1512 + (J << 2) >> 2] | 0;
-   a : do if (!t) {
-    K = f;
-    L = 0;
-    M = 0;
-    N = 86;
-   } else {
-    u = f;
-    j = 0;
-    s = e << ((J | 0) == 31 ? 0 : 25 - (J >>> 1) | 0);
-    o = t;
-    i = 0;
-    while (1) {
-     m = k[o + 4 >> 2] & -8;
-     l = m - e | 0;
-     if (l >>> 0 < u >>> 0) if ((m | 0) == (e | 0)) {
-      O = l;
-      P = o;
-      Q = o;
-      N = 90;
-      break a;
-     } else {
-      R = l;
-      S = o;
-     } else {
-      R = u;
-      S = i;
-     }
-     l = k[o + 20 >> 2] | 0;
-     o = k[o + 16 + (s >>> 31 << 2) >> 2] | 0;
-     m = (l | 0) == 0 | (l | 0) == (o | 0) ? j : l;
-     l = (o | 0) == 0;
-     if (l) {
-      K = R;
-      L = m;
-      M = S;
-      N = 86;
-      break;
-     } else {
-      u = R;
-      j = m;
-      s = s << (l & 1 ^ 1);
-      i = S;
-     }
-    }
-   } while (0);
-   if ((N | 0) == 86) {
-    if ((L | 0) == 0 & (M | 0) == 0) {
-     t = 2 << J;
-     f = q & (t | 0 - t);
-     if (!f) {
-      y = e;
-      break;
-     }
-     t = (f & 0 - f) + -1 | 0;
-     f = t >>> 12 & 16;
-     d = t >>> f;
-     t = d >>> 5 & 8;
-     g = d >>> t;
-     d = g >>> 2 & 4;
-     i = g >>> d;
-     g = i >>> 1 & 2;
-     s = i >>> g;
-     i = s >>> 1 & 1;
-     T = k[1512 + ((t | f | d | g | i) + (s >>> i) << 2) >> 2] | 0;
-    } else T = L;
-    if (!T) {
-     U = K;
-     V = M;
-    } else {
-     O = K;
-     P = T;
-     Q = M;
-     N = 90;
-    }
-   }
-   if ((N | 0) == 90) while (1) {
-    N = 0;
-    i = (k[P + 4 >> 2] & -8) - e | 0;
-    s = i >>> 0 < O >>> 0;
-    g = s ? i : O;
-    i = s ? P : Q;
-    s = k[P + 16 >> 2] | 0;
-    if (s | 0) {
-     O = g;
-     P = s;
-     Q = i;
-     N = 90;
-     continue;
-    }
-    P = k[P + 20 >> 2] | 0;
-    if (!P) {
-     U = g;
-     V = i;
-     break;
-    } else {
-     O = g;
-     Q = i;
-     N = 90;
-    }
-   }
-   if (!V) y = e; else if (U >>> 0 < ((k[304] | 0) - e | 0) >>> 0) {
-    q = k[306] | 0;
-    if (V >>> 0 < q >>> 0) qa();
-    i = V + e | 0;
-    if (V >>> 0 >= i >>> 0) qa();
-    g = k[V + 24 >> 2] | 0;
-    s = k[V + 12 >> 2] | 0;
-    do if ((s | 0) == (V | 0)) {
-     d = V + 20 | 0;
-     f = k[d >> 2] | 0;
-     if (!f) {
-      t = V + 16 | 0;
-      j = k[t >> 2] | 0;
-      if (!j) {
-       W = 0;
-       break;
-      } else {
-       X = j;
-       Y = t;
-      }
-     } else {
-      X = f;
-      Y = d;
-     }
-     while (1) {
-      d = X + 20 | 0;
-      f = k[d >> 2] | 0;
-      if (f | 0) {
-       X = f;
-       Y = d;
-       continue;
-      }
-      d = X + 16 | 0;
-      f = k[d >> 2] | 0;
-      if (!f) {
-       Z = X;
-       _ = Y;
-       break;
-      } else {
-       X = f;
-       Y = d;
-      }
-     }
-     if (_ >>> 0 < q >>> 0) qa(); else {
-      k[_ >> 2] = 0;
-      W = Z;
-      break;
-     }
-    } else {
-     d = k[V + 8 >> 2] | 0;
-     if (d >>> 0 < q >>> 0) qa();
-     f = d + 12 | 0;
-     if ((k[f >> 2] | 0) != (V | 0)) qa();
-     t = s + 8 | 0;
-     if ((k[t >> 2] | 0) == (V | 0)) {
-      k[f >> 2] = s;
-      k[t >> 2] = d;
-      W = s;
-      break;
-     } else qa();
-    } while (0);
-    do if (g | 0) {
-     s = k[V + 28 >> 2] | 0;
-     q = 1512 + (s << 2) | 0;
-     if ((V | 0) == (k[q >> 2] | 0)) {
-      k[q >> 2] = W;
-      if (!W) {
-       k[303] = k[303] & ~(1 << s);
-       break;
-      }
-     } else {
-      if (g >>> 0 < (k[306] | 0) >>> 0) qa();
-      s = g + 16 | 0;
-      if ((k[s >> 2] | 0) == (V | 0)) k[s >> 2] = W; else k[g + 20 >> 2] = W;
-      if (!W) break;
-     }
-     s = k[306] | 0;
-     if (W >>> 0 < s >>> 0) qa();
-     k[W + 24 >> 2] = g;
-     q = k[V + 16 >> 2] | 0;
-     do if (q | 0) if (q >>> 0 < s >>> 0) qa(); else {
-      k[W + 16 >> 2] = q;
-      k[q + 24 >> 2] = W;
-      break;
-     } while (0);
-     q = k[V + 20 >> 2] | 0;
-     if (q | 0) if (q >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-      k[W + 20 >> 2] = q;
-      k[q + 24 >> 2] = W;
-      break;
-     }
-    } while (0);
-    do if (U >>> 0 < 16) {
-     g = U + e | 0;
-     k[V + 4 >> 2] = g | 3;
-     q = V + g + 4 | 0;
-     k[q >> 2] = k[q >> 2] | 1;
-    } else {
-     k[V + 4 >> 2] = e | 3;
-     k[i + 4 >> 2] = U | 1;
-     k[i + U >> 2] = U;
-     q = U >>> 3;
-     if (U >>> 0 < 256) {
-      g = 1248 + (q << 1 << 2) | 0;
-      s = k[302] | 0;
-      d = 1 << q;
-      if (!(s & d)) {
-       k[302] = s | d;
-       $ = g + 8 | 0;
-       aa = g;
-      } else {
-       d = g + 8 | 0;
-       s = k[d >> 2] | 0;
-       if (s >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-        $ = d;
-        aa = s;
-       }
-      }
-      k[$ >> 2] = i;
-      k[aa + 12 >> 2] = i;
-      k[i + 8 >> 2] = aa;
-      k[i + 12 >> 2] = g;
-      break;
-     }
-     g = U >>> 8;
-     if (!g) ba = 0; else if (U >>> 0 > 16777215) ba = 31; else {
-      s = (g + 1048320 | 0) >>> 16 & 8;
-      d = g << s;
-      g = (d + 520192 | 0) >>> 16 & 4;
-      q = d << g;
-      d = (q + 245760 | 0) >>> 16 & 2;
-      t = 14 - (g | s | d) + (q << d >>> 15) | 0;
-      ba = U >>> (t + 7 | 0) & 1 | t << 1;
-     }
-     t = 1512 + (ba << 2) | 0;
-     k[i + 28 >> 2] = ba;
-     d = i + 16 | 0;
-     k[d + 4 >> 2] = 0;
-     k[d >> 2] = 0;
-     d = k[303] | 0;
-     q = 1 << ba;
-     if (!(d & q)) {
-      k[303] = d | q;
-      k[t >> 2] = i;
-      k[i + 24 >> 2] = t;
-      k[i + 12 >> 2] = i;
-      k[i + 8 >> 2] = i;
-      break;
-     }
-     q = U << ((ba | 0) == 31 ? 0 : 25 - (ba >>> 1) | 0);
-     d = k[t >> 2] | 0;
-     while (1) {
-      if ((k[d + 4 >> 2] & -8 | 0) == (U | 0)) {
-       ca = d;
-       N = 148;
-       break;
-      }
-      t = d + 16 + (q >>> 31 << 2) | 0;
-      s = k[t >> 2] | 0;
-      if (!s) {
-       da = t;
-       ea = d;
-       N = 145;
-       break;
-      } else {
-       q = q << 1;
-       d = s;
-      }
-     }
-     if ((N | 0) == 145) if (da >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-      k[da >> 2] = i;
-      k[i + 24 >> 2] = ea;
-      k[i + 12 >> 2] = i;
-      k[i + 8 >> 2] = i;
-      break;
-     } else if ((N | 0) == 148) {
-      d = ca + 8 | 0;
-      q = k[d >> 2] | 0;
-      s = k[306] | 0;
-      if (q >>> 0 >= s >>> 0 & ca >>> 0 >= s >>> 0) {
-       k[q + 12 >> 2] = i;
-       k[d >> 2] = i;
-       k[i + 8 >> 2] = q;
-       k[i + 12 >> 2] = ca;
-       k[i + 24 >> 2] = 0;
-       break;
-      } else qa();
-     }
-    } while (0);
-    p = V + 8 | 0;
-    r = b;
-    return p | 0;
-   } else y = e;
-  }
- } while (0);
- V = k[304] | 0;
- if (V >>> 0 >= y >>> 0) {
-  ca = V - y | 0;
-  ea = k[307] | 0;
-  if (ca >>> 0 > 15) {
-   da = ea + y | 0;
-   k[307] = da;
-   k[304] = ca;
-   k[da + 4 >> 2] = ca | 1;
-   k[da + ca >> 2] = ca;
-   k[ea + 4 >> 2] = y | 3;
-  } else {
-   k[304] = 0;
-   k[307] = 0;
-   k[ea + 4 >> 2] = V | 3;
-   ca = ea + V + 4 | 0;
-   k[ca >> 2] = k[ca >> 2] | 1;
-  }
-  p = ea + 8 | 0;
-  r = b;
-  return p | 0;
- }
- ea = k[305] | 0;
- if (ea >>> 0 > y >>> 0) {
-  ca = ea - y | 0;
-  k[305] = ca;
-  ea = k[308] | 0;
-  V = ea + y | 0;
-  k[308] = V;
-  k[V + 4 >> 2] = ca | 1;
-  k[ea + 4 >> 2] = y | 3;
-  p = ea + 8 | 0;
-  r = b;
-  return p | 0;
- }
- if (!(k[420] | 0)) {
-  k[422] = 4096;
-  k[421] = 4096;
-  k[423] = -1;
-  k[424] = -1;
-  k[425] = 0;
-  k[413] = 0;
-  ea = c & -16 ^ 1431655768;
-  k[c >> 2] = ea;
-  k[420] = ea;
- }
- ea = y + 48 | 0;
- c = k[422] | 0;
- ca = y + 47 | 0;
- V = c + ca | 0;
- da = 0 - c | 0;
- c = V & da;
- if (c >>> 0 <= y >>> 0) {
-  p = 0;
-  r = b;
-  return p | 0;
- }
- U = k[412] | 0;
- if (U | 0) {
-  ba = k[410] | 0;
-  aa = ba + c | 0;
-  if (aa >>> 0 <= ba >>> 0 | aa >>> 0 > U >>> 0) {
-   p = 0;
-   r = b;
-   return p | 0;
-  }
- }
- b : do if (!(k[413] & 4)) {
-  U = k[308] | 0;
-  c : do if (!U) N = 171; else {
-   aa = 1656;
-   while (1) {
-    ba = k[aa >> 2] | 0;
-    if (ba >>> 0 <= U >>> 0) {
-     $ = aa + 4 | 0;
-     if ((ba + (k[$ >> 2] | 0) | 0) >>> 0 > U >>> 0) {
-      fa = aa;
-      ga = $;
-      break;
-     }
-    }
-    aa = k[aa + 8 >> 2] | 0;
-    if (!aa) {
-     N = 171;
-     break c;
-    }
-   }
-   aa = V - (k[305] | 0) & da;
-   if (aa >>> 0 < 2147483647) {
-    $ = ta(aa | 0) | 0;
-    if (($ | 0) == ((k[fa >> 2] | 0) + (k[ga >> 2] | 0) | 0)) {
-     if (($ | 0) != (-1 | 0)) {
-      ha = $;
-      ia = aa;
-      N = 191;
-      break b;
-     }
-    } else {
-     ja = $;
-     ka = aa;
-     N = 181;
-    }
-   }
-  } while (0);
-  do if ((N | 0) == 171) {
-   U = ta(0) | 0;
-   if ((U | 0) != (-1 | 0)) {
-    e = U;
-    aa = k[421] | 0;
-    $ = aa + -1 | 0;
-    if (!($ & e)) la = c; else la = c - e + ($ + e & 0 - aa) | 0;
-    aa = k[410] | 0;
-    e = aa + la | 0;
-    if (la >>> 0 > y >>> 0 & la >>> 0 < 2147483647) {
-     $ = k[412] | 0;
-     if ($ | 0) if (e >>> 0 <= aa >>> 0 | e >>> 0 > $ >>> 0) break;
-     $ = ta(la | 0) | 0;
-     if (($ | 0) == (U | 0)) {
-      ha = U;
-      ia = la;
-      N = 191;
-      break b;
-     } else {
-      ja = $;
-      ka = la;
-      N = 181;
-     }
-    }
-   }
-  } while (0);
-  d : do if ((N | 0) == 181) {
-   $ = 0 - ka | 0;
-   do if (ea >>> 0 > ka >>> 0 & (ka >>> 0 < 2147483647 & (ja | 0) != (-1 | 0))) {
-    U = k[422] | 0;
-    e = ca - ka + U & 0 - U;
-    if (e >>> 0 < 2147483647) if ((ta(e | 0) | 0) == (-1 | 0)) {
-     ta($ | 0) | 0;
-     break d;
-    } else {
-     ma = e + ka | 0;
-     break;
-    } else ma = ka;
-   } else ma = ka; while (0);
-   if ((ja | 0) != (-1 | 0)) {
-    ha = ja;
-    ia = ma;
-    N = 191;
-    break b;
-   }
-  } while (0);
-  k[413] = k[413] | 4;
-  N = 188;
- } else N = 188; while (0);
- if ((N | 0) == 188) if (c >>> 0 < 2147483647) {
-  ma = ta(c | 0) | 0;
-  c = ta(0) | 0;
-  if (ma >>> 0 < c >>> 0 & ((ma | 0) != (-1 | 0) & (c | 0) != (-1 | 0))) {
-   ja = c - ma | 0;
-   if (ja >>> 0 > (y + 40 | 0) >>> 0) {
-    ha = ma;
-    ia = ja;
-    N = 191;
-   }
-  }
- }
- if ((N | 0) == 191) {
-  ja = (k[410] | 0) + ia | 0;
-  k[410] = ja;
-  if (ja >>> 0 > (k[411] | 0) >>> 0) k[411] = ja;
-  ja = k[308] | 0;
-  do if (!ja) {
-   ma = k[306] | 0;
-   if ((ma | 0) == 0 | ha >>> 0 < ma >>> 0) k[306] = ha;
-   k[414] = ha;
-   k[415] = ia;
-   k[417] = 0;
-   k[311] = k[420];
-   k[310] = -1;
-   ma = 0;
-   do {
-    c = 1248 + (ma << 1 << 2) | 0;
-    k[c + 12 >> 2] = c;
-    k[c + 8 >> 2] = c;
-    ma = ma + 1 | 0;
-   } while ((ma | 0) != 32);
-   ma = ha + 8 | 0;
-   c = (ma & 7 | 0) == 0 ? 0 : 0 - ma & 7;
-   ma = ha + c | 0;
-   ka = ia + -40 - c | 0;
-   k[308] = ma;
-   k[305] = ka;
-   k[ma + 4 >> 2] = ka | 1;
-   k[ma + ka + 4 >> 2] = 40;
-   k[309] = k[424];
-  } else {
-   ka = 1656;
-   do {
-    ma = k[ka >> 2] | 0;
-    c = ka + 4 | 0;
-    ca = k[c >> 2] | 0;
-    if ((ha | 0) == (ma + ca | 0)) {
-     na = ma;
-     oa = c;
-     pa = ca;
-     ra = ka;
-     N = 201;
-     break;
-    }
-    ka = k[ka + 8 >> 2] | 0;
-   } while ((ka | 0) != 0);
-   if ((N | 0) == 201) if (!(k[ra + 12 >> 2] & 8)) if (ja >>> 0 < ha >>> 0 & ja >>> 0 >= na >>> 0) {
-    k[oa >> 2] = pa + ia;
-    ka = ja + 8 | 0;
-    ca = (ka & 7 | 0) == 0 ? 0 : 0 - ka & 7;
-    ka = ja + ca | 0;
-    c = ia - ca + (k[305] | 0) | 0;
-    k[308] = ka;
-    k[305] = c;
-    k[ka + 4 >> 2] = c | 1;
-    k[ka + c + 4 >> 2] = 40;
-    k[309] = k[424];
-    break;
-   }
-   c = k[306] | 0;
-   if (ha >>> 0 < c >>> 0) {
-    k[306] = ha;
-    sa = ha;
-   } else sa = c;
-   c = ha + ia | 0;
-   ka = 1656;
-   while (1) {
-    if ((k[ka >> 2] | 0) == (c | 0)) {
-     ua = ka;
-     va = ka;
-     N = 209;
-     break;
-    }
-    ka = k[ka + 8 >> 2] | 0;
-    if (!ka) {
-     wa = 1656;
-     break;
-    }
-   }
-   if ((N | 0) == 209) if (!(k[va + 12 >> 2] & 8)) {
-    k[ua >> 2] = ha;
-    ka = va + 4 | 0;
-    k[ka >> 2] = (k[ka >> 2] | 0) + ia;
-    ka = ha + 8 | 0;
-    ca = ha + ((ka & 7 | 0) == 0 ? 0 : 0 - ka & 7) | 0;
-    ka = c + 8 | 0;
-    ma = c + ((ka & 7 | 0) == 0 ? 0 : 0 - ka & 7) | 0;
-    ka = ca + y | 0;
-    ea = ma - ca - y | 0;
-    k[ca + 4 >> 2] = y | 3;
-    do if ((ma | 0) == (ja | 0)) {
-     la = (k[305] | 0) + ea | 0;
-     k[305] = la;
-     k[308] = ka;
-     k[ka + 4 >> 2] = la | 1;
-    } else {
-     if ((ma | 0) == (k[307] | 0)) {
-      la = (k[304] | 0) + ea | 0;
-      k[304] = la;
-      k[307] = ka;
-      k[ka + 4 >> 2] = la | 1;
-      k[ka + la >> 2] = la;
-      break;
-     }
-     la = k[ma + 4 >> 2] | 0;
-     if ((la & 3 | 0) == 1) {
-      ga = la & -8;
-      fa = la >>> 3;
-      e : do if (la >>> 0 < 256) {
-       da = k[ma + 8 >> 2] | 0;
-       V = k[ma + 12 >> 2] | 0;
-       $ = 1248 + (fa << 1 << 2) | 0;
-       do if ((da | 0) != ($ | 0)) {
-        if (da >>> 0 < sa >>> 0) qa();
-        if ((k[da + 12 >> 2] | 0) == (ma | 0)) break;
-        qa();
-       } while (0);
-       if ((V | 0) == (da | 0)) {
-        k[302] = k[302] & ~(1 << fa);
-        break;
-       }
-       do if ((V | 0) == ($ | 0)) xa = V + 8 | 0; else {
-        if (V >>> 0 < sa >>> 0) qa();
-        e = V + 8 | 0;
-        if ((k[e >> 2] | 0) == (ma | 0)) {
-         xa = e;
-         break;
-        }
-        qa();
-       } while (0);
-       k[da + 12 >> 2] = V;
-       k[xa >> 2] = da;
-      } else {
-       $ = k[ma + 24 >> 2] | 0;
-       e = k[ma + 12 >> 2] | 0;
-       do if ((e | 0) == (ma | 0)) {
-        U = ma + 16 | 0;
-        aa = U + 4 | 0;
-        ba = k[aa >> 2] | 0;
-        if (!ba) {
-         W = k[U >> 2] | 0;
-         if (!W) {
-          ya = 0;
-          break;
-         } else {
-          za = W;
-          Aa = U;
-         }
-        } else {
-         za = ba;
-         Aa = aa;
-        }
-        while (1) {
-         aa = za + 20 | 0;
-         ba = k[aa >> 2] | 0;
-         if (ba | 0) {
-          za = ba;
-          Aa = aa;
-          continue;
-         }
-         aa = za + 16 | 0;
-         ba = k[aa >> 2] | 0;
-         if (!ba) {
-          Ba = za;
-          Ca = Aa;
-          break;
-         } else {
-          za = ba;
-          Aa = aa;
-         }
-        }
-        if (Ca >>> 0 < sa >>> 0) qa(); else {
-         k[Ca >> 2] = 0;
-         ya = Ba;
-         break;
-        }
-       } else {
-        aa = k[ma + 8 >> 2] | 0;
-        if (aa >>> 0 < sa >>> 0) qa();
-        ba = aa + 12 | 0;
-        if ((k[ba >> 2] | 0) != (ma | 0)) qa();
-        U = e + 8 | 0;
-        if ((k[U >> 2] | 0) == (ma | 0)) {
-         k[ba >> 2] = e;
-         k[U >> 2] = aa;
-         ya = e;
-         break;
-        } else qa();
-       } while (0);
-       if (!$) break;
-       e = k[ma + 28 >> 2] | 0;
-       da = 1512 + (e << 2) | 0;
-       do if ((ma | 0) == (k[da >> 2] | 0)) {
-        k[da >> 2] = ya;
-        if (ya | 0) break;
-        k[303] = k[303] & ~(1 << e);
-        break e;
-       } else {
-        if ($ >>> 0 < (k[306] | 0) >>> 0) qa();
-        V = $ + 16 | 0;
-        if ((k[V >> 2] | 0) == (ma | 0)) k[V >> 2] = ya; else k[$ + 20 >> 2] = ya;
-        if (!ya) break e;
-       } while (0);
-       e = k[306] | 0;
-       if (ya >>> 0 < e >>> 0) qa();
-       k[ya + 24 >> 2] = $;
-       da = ma + 16 | 0;
-       V = k[da >> 2] | 0;
-       do if (V | 0) if (V >>> 0 < e >>> 0) qa(); else {
-        k[ya + 16 >> 2] = V;
-        k[V + 24 >> 2] = ya;
-        break;
-       } while (0);
-       V = k[da + 4 >> 2] | 0;
-       if (!V) break;
-       if (V >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-        k[ya + 20 >> 2] = V;
-        k[V + 24 >> 2] = ya;
-        break;
-       }
-      } while (0);
-      Da = ma + ga | 0;
-      Ea = ga + ea | 0;
-     } else {
-      Da = ma;
-      Ea = ea;
-     }
-     fa = Da + 4 | 0;
-     k[fa >> 2] = k[fa >> 2] & -2;
-     k[ka + 4 >> 2] = Ea | 1;
-     k[ka + Ea >> 2] = Ea;
-     fa = Ea >>> 3;
-     if (Ea >>> 0 < 256) {
-      la = 1248 + (fa << 1 << 2) | 0;
-      V = k[302] | 0;
-      e = 1 << fa;
-      do if (!(V & e)) {
-       k[302] = V | e;
-       Fa = la + 8 | 0;
-       Ga = la;
-      } else {
-       fa = la + 8 | 0;
-       $ = k[fa >> 2] | 0;
-       if ($ >>> 0 >= (k[306] | 0) >>> 0) {
-        Fa = fa;
-        Ga = $;
-        break;
-       }
-       qa();
-      } while (0);
-      k[Fa >> 2] = ka;
-      k[Ga + 12 >> 2] = ka;
-      k[ka + 8 >> 2] = Ga;
-      k[ka + 12 >> 2] = la;
-      break;
-     }
-     e = Ea >>> 8;
-     do if (!e) Ha = 0; else {
-      if (Ea >>> 0 > 16777215) {
-       Ha = 31;
-       break;
-      }
-      V = (e + 1048320 | 0) >>> 16 & 8;
-      ga = e << V;
-      $ = (ga + 520192 | 0) >>> 16 & 4;
-      fa = ga << $;
-      ga = (fa + 245760 | 0) >>> 16 & 2;
-      aa = 14 - ($ | V | ga) + (fa << ga >>> 15) | 0;
-      Ha = Ea >>> (aa + 7 | 0) & 1 | aa << 1;
-     } while (0);
-     e = 1512 + (Ha << 2) | 0;
-     k[ka + 28 >> 2] = Ha;
-     la = ka + 16 | 0;
-     k[la + 4 >> 2] = 0;
-     k[la >> 2] = 0;
-     la = k[303] | 0;
-     aa = 1 << Ha;
-     if (!(la & aa)) {
-      k[303] = la | aa;
-      k[e >> 2] = ka;
-      k[ka + 24 >> 2] = e;
-      k[ka + 12 >> 2] = ka;
-      k[ka + 8 >> 2] = ka;
-      break;
-     }
-     aa = Ea << ((Ha | 0) == 31 ? 0 : 25 - (Ha >>> 1) | 0);
-     la = k[e >> 2] | 0;
-     while (1) {
-      if ((k[la + 4 >> 2] & -8 | 0) == (Ea | 0)) {
-       Ia = la;
-       N = 279;
-       break;
-      }
-      e = la + 16 + (aa >>> 31 << 2) | 0;
-      ga = k[e >> 2] | 0;
-      if (!ga) {
-       Ja = e;
-       Ka = la;
-       N = 276;
-       break;
-      } else {
-       aa = aa << 1;
-       la = ga;
-      }
-     }
-     if ((N | 0) == 276) if (Ja >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-      k[Ja >> 2] = ka;
-      k[ka + 24 >> 2] = Ka;
-      k[ka + 12 >> 2] = ka;
-      k[ka + 8 >> 2] = ka;
-      break;
-     } else if ((N | 0) == 279) {
-      la = Ia + 8 | 0;
-      aa = k[la >> 2] | 0;
-      ga = k[306] | 0;
-      if (aa >>> 0 >= ga >>> 0 & Ia >>> 0 >= ga >>> 0) {
-       k[aa + 12 >> 2] = ka;
-       k[la >> 2] = ka;
-       k[ka + 8 >> 2] = aa;
-       k[ka + 12 >> 2] = Ia;
-       k[ka + 24 >> 2] = 0;
-       break;
-      } else qa();
-     }
-    } while (0);
-    p = ca + 8 | 0;
-    r = b;
-    return p | 0;
-   } else wa = 1656;
-   while (1) {
-    ka = k[wa >> 2] | 0;
-    if (ka >>> 0 <= ja >>> 0) {
-     ea = ka + (k[wa + 4 >> 2] | 0) | 0;
-     if (ea >>> 0 > ja >>> 0) {
-      La = ea;
-      break;
-     }
-    }
-    wa = k[wa + 8 >> 2] | 0;
-   }
-   ca = La + -47 | 0;
-   ea = ca + 8 | 0;
-   ka = ca + ((ea & 7 | 0) == 0 ? 0 : 0 - ea & 7) | 0;
-   ea = ja + 16 | 0;
-   ca = ka >>> 0 < ea >>> 0 ? ja : ka;
-   ka = ca + 8 | 0;
-   ma = ha + 8 | 0;
-   c = (ma & 7 | 0) == 0 ? 0 : 0 - ma & 7;
-   ma = ha + c | 0;
-   aa = ia + -40 - c | 0;
-   k[308] = ma;
-   k[305] = aa;
-   k[ma + 4 >> 2] = aa | 1;
-   k[ma + aa + 4 >> 2] = 40;
-   k[309] = k[424];
-   aa = ca + 4 | 0;
-   k[aa >> 2] = 27;
-   k[ka >> 2] = k[414];
-   k[ka + 4 >> 2] = k[415];
-   k[ka + 8 >> 2] = k[416];
-   k[ka + 12 >> 2] = k[417];
-   k[414] = ha;
-   k[415] = ia;
-   k[417] = 0;
-   k[416] = ka;
-   ka = ca + 24 | 0;
-   do {
-    ka = ka + 4 | 0;
-    k[ka >> 2] = 7;
-   } while ((ka + 4 | 0) >>> 0 < La >>> 0);
-   if ((ca | 0) != (ja | 0)) {
-    ka = ca - ja | 0;
-    k[aa >> 2] = k[aa >> 2] & -2;
-    k[ja + 4 >> 2] = ka | 1;
-    k[ca >> 2] = ka;
-    ma = ka >>> 3;
-    if (ka >>> 0 < 256) {
-     c = 1248 + (ma << 1 << 2) | 0;
-     la = k[302] | 0;
-     ga = 1 << ma;
-     if (!(la & ga)) {
-      k[302] = la | ga;
-      Ma = c + 8 | 0;
-      Na = c;
-     } else {
-      ga = c + 8 | 0;
-      la = k[ga >> 2] | 0;
-      if (la >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-       Ma = ga;
-       Na = la;
-      }
-     }
-     k[Ma >> 2] = ja;
-     k[Na + 12 >> 2] = ja;
-     k[ja + 8 >> 2] = Na;
-     k[ja + 12 >> 2] = c;
-     break;
-    }
-    c = ka >>> 8;
-    if (!c) Oa = 0; else if (ka >>> 0 > 16777215) Oa = 31; else {
-     la = (c + 1048320 | 0) >>> 16 & 8;
-     ga = c << la;
-     c = (ga + 520192 | 0) >>> 16 & 4;
-     ma = ga << c;
-     ga = (ma + 245760 | 0) >>> 16 & 2;
-     e = 14 - (c | la | ga) + (ma << ga >>> 15) | 0;
-     Oa = ka >>> (e + 7 | 0) & 1 | e << 1;
-    }
-    e = 1512 + (Oa << 2) | 0;
-    k[ja + 28 >> 2] = Oa;
-    k[ja + 20 >> 2] = 0;
-    k[ea >> 2] = 0;
-    ga = k[303] | 0;
-    ma = 1 << Oa;
-    if (!(ga & ma)) {
-     k[303] = ga | ma;
-     k[e >> 2] = ja;
-     k[ja + 24 >> 2] = e;
-     k[ja + 12 >> 2] = ja;
-     k[ja + 8 >> 2] = ja;
-     break;
-    }
-    ma = ka << ((Oa | 0) == 31 ? 0 : 25 - (Oa >>> 1) | 0);
-    ga = k[e >> 2] | 0;
-    while (1) {
-     if ((k[ga + 4 >> 2] & -8 | 0) == (ka | 0)) {
-      Pa = ga;
-      N = 305;
-      break;
-     }
-     e = ga + 16 + (ma >>> 31 << 2) | 0;
-     la = k[e >> 2] | 0;
-     if (!la) {
-      Ra = e;
-      Sa = ga;
-      N = 302;
-      break;
-     } else {
-      ma = ma << 1;
-      ga = la;
-     }
-    }
-    if ((N | 0) == 302) if (Ra >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-     k[Ra >> 2] = ja;
-     k[ja + 24 >> 2] = Sa;
-     k[ja + 12 >> 2] = ja;
-     k[ja + 8 >> 2] = ja;
-     break;
-    } else if ((N | 0) == 305) {
-     ga = Pa + 8 | 0;
-     ma = k[ga >> 2] | 0;
-     ka = k[306] | 0;
-     if (ma >>> 0 >= ka >>> 0 & Pa >>> 0 >= ka >>> 0) {
-      k[ma + 12 >> 2] = ja;
-      k[ga >> 2] = ja;
-      k[ja + 8 >> 2] = ma;
-      k[ja + 12 >> 2] = Pa;
-      k[ja + 24 >> 2] = 0;
-      break;
-     } else qa();
-    }
-   }
-  } while (0);
-  ja = k[305] | 0;
-  if (ja >>> 0 > y >>> 0) {
-   Pa = ja - y | 0;
-   k[305] = Pa;
-   ja = k[308] | 0;
-   N = ja + y | 0;
-   k[308] = N;
-   k[N + 4 >> 2] = Pa | 1;
-   k[ja + 4 >> 2] = y | 3;
-   p = ja + 8 | 0;
-   r = b;
-   return p | 0;
-  }
- }
- ja = Qa() | 0;
- k[ja >> 2] = 12;
- p = 0;
- r = b;
- return p | 0;
-}
-
-function fb(a) {
- a = a | 0;
- var b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, i = 0, j = 0, l = 0, m = 0, n = 0, o = 0, p = 0, q = 0, r = 0, s = 0, t = 0, u = 0, v = 0, w = 0, x = 0, y = 0, z = 0, A = 0, B = 0, C = 0, D = 0, E = 0, F = 0, G = 0, H = 0, I = 0, J = 0, K = 0, L = 0;
- if (!a) return;
- b = a + -8 | 0;
- c = k[306] | 0;
- if (b >>> 0 < c >>> 0) qa();
- d = k[a + -4 >> 2] | 0;
- a = d & 3;
- if ((a | 0) == 1) qa();
- e = d & -8;
- f = b + e | 0;
- do if (!(d & 1)) {
-  g = k[b >> 2] | 0;
-  if (!a) return;
-  h = b + (0 - g) | 0;
-  i = g + e | 0;
-  if (h >>> 0 < c >>> 0) qa();
-  if ((h | 0) == (k[307] | 0)) {
-   j = f + 4 | 0;
-   l = k[j >> 2] | 0;
-   if ((l & 3 | 0) != 3) {
-    m = h;
-    n = i;
-    break;
-   }
-   k[304] = i;
-   k[j >> 2] = l & -2;
-   k[h + 4 >> 2] = i | 1;
-   k[h + i >> 2] = i;
-   return;
-  }
-  l = g >>> 3;
-  if (g >>> 0 < 256) {
-   g = k[h + 8 >> 2] | 0;
-   j = k[h + 12 >> 2] | 0;
-   o = 1248 + (l << 1 << 2) | 0;
-   if ((g | 0) != (o | 0)) {
-    if (g >>> 0 < c >>> 0) qa();
-    if ((k[g + 12 >> 2] | 0) != (h | 0)) qa();
-   }
-   if ((j | 0) == (g | 0)) {
-    k[302] = k[302] & ~(1 << l);
-    m = h;
-    n = i;
-    break;
-   }
-   if ((j | 0) == (o | 0)) p = j + 8 | 0; else {
-    if (j >>> 0 < c >>> 0) qa();
-    o = j + 8 | 0;
-    if ((k[o >> 2] | 0) == (h | 0)) p = o; else qa();
-   }
-   k[g + 12 >> 2] = j;
-   k[p >> 2] = g;
-   m = h;
-   n = i;
-   break;
-  }
-  g = k[h + 24 >> 2] | 0;
-  j = k[h + 12 >> 2] | 0;
-  do if ((j | 0) == (h | 0)) {
-   o = h + 16 | 0;
-   l = o + 4 | 0;
-   q = k[l >> 2] | 0;
-   if (!q) {
-    r = k[o >> 2] | 0;
-    if (!r) {
-     s = 0;
-     break;
-    } else {
-     t = r;
-     u = o;
-    }
-   } else {
-    t = q;
-    u = l;
-   }
-   while (1) {
-    l = t + 20 | 0;
-    q = k[l >> 2] | 0;
-    if (q | 0) {
-     t = q;
-     u = l;
-     continue;
-    }
-    l = t + 16 | 0;
-    q = k[l >> 2] | 0;
-    if (!q) {
-     v = t;
-     w = u;
-     break;
-    } else {
-     t = q;
-     u = l;
-    }
-   }
-   if (w >>> 0 < c >>> 0) qa(); else {
-    k[w >> 2] = 0;
-    s = v;
-    break;
-   }
-  } else {
-   l = k[h + 8 >> 2] | 0;
-   if (l >>> 0 < c >>> 0) qa();
-   q = l + 12 | 0;
-   if ((k[q >> 2] | 0) != (h | 0)) qa();
-   o = j + 8 | 0;
-   if ((k[o >> 2] | 0) == (h | 0)) {
-    k[q >> 2] = j;
-    k[o >> 2] = l;
-    s = j;
-    break;
-   } else qa();
-  } while (0);
-  if (!g) {
-   m = h;
-   n = i;
-  } else {
-   j = k[h + 28 >> 2] | 0;
-   l = 1512 + (j << 2) | 0;
-   if ((h | 0) == (k[l >> 2] | 0)) {
-    k[l >> 2] = s;
-    if (!s) {
-     k[303] = k[303] & ~(1 << j);
-     m = h;
-     n = i;
-     break;
-    }
-   } else {
-    if (g >>> 0 < (k[306] | 0) >>> 0) qa();
-    j = g + 16 | 0;
-    if ((k[j >> 2] | 0) == (h | 0)) k[j >> 2] = s; else k[g + 20 >> 2] = s;
-    if (!s) {
-     m = h;
-     n = i;
-     break;
-    }
-   }
-   j = k[306] | 0;
-   if (s >>> 0 < j >>> 0) qa();
-   k[s + 24 >> 2] = g;
-   l = h + 16 | 0;
-   o = k[l >> 2] | 0;
-   do if (o | 0) if (o >>> 0 < j >>> 0) qa(); else {
-    k[s + 16 >> 2] = o;
-    k[o + 24 >> 2] = s;
-    break;
-   } while (0);
-   o = k[l + 4 >> 2] | 0;
-   if (!o) {
-    m = h;
-    n = i;
-   } else if (o >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-    k[s + 20 >> 2] = o;
-    k[o + 24 >> 2] = s;
-    m = h;
-    n = i;
-    break;
-   }
-  }
- } else {
-  m = b;
-  n = e;
- } while (0);
- if (m >>> 0 >= f >>> 0) qa();
- e = f + 4 | 0;
- b = k[e >> 2] | 0;
- if (!(b & 1)) qa();
- if (!(b & 2)) {
-  if ((f | 0) == (k[308] | 0)) {
-   s = (k[305] | 0) + n | 0;
-   k[305] = s;
-   k[308] = m;
-   k[m + 4 >> 2] = s | 1;
-   if ((m | 0) != (k[307] | 0)) return;
-   k[307] = 0;
-   k[304] = 0;
-   return;
-  }
-  if ((f | 0) == (k[307] | 0)) {
-   s = (k[304] | 0) + n | 0;
-   k[304] = s;
-   k[307] = m;
-   k[m + 4 >> 2] = s | 1;
-   k[m + s >> 2] = s;
-   return;
-  }
-  s = (b & -8) + n | 0;
-  c = b >>> 3;
-  do if (b >>> 0 < 256) {
-   v = k[f + 8 >> 2] | 0;
-   w = k[f + 12 >> 2] | 0;
-   u = 1248 + (c << 1 << 2) | 0;
-   if ((v | 0) != (u | 0)) {
-    if (v >>> 0 < (k[306] | 0) >>> 0) qa();
-    if ((k[v + 12 >> 2] | 0) != (f | 0)) qa();
-   }
-   if ((w | 0) == (v | 0)) {
-    k[302] = k[302] & ~(1 << c);
-    break;
-   }
-   if ((w | 0) == (u | 0)) x = w + 8 | 0; else {
-    if (w >>> 0 < (k[306] | 0) >>> 0) qa();
-    u = w + 8 | 0;
-    if ((k[u >> 2] | 0) == (f | 0)) x = u; else qa();
-   }
-   k[v + 12 >> 2] = w;
-   k[x >> 2] = v;
-  } else {
-   v = k[f + 24 >> 2] | 0;
-   w = k[f + 12 >> 2] | 0;
-   do if ((w | 0) == (f | 0)) {
-    u = f + 16 | 0;
-    t = u + 4 | 0;
-    p = k[t >> 2] | 0;
-    if (!p) {
-     a = k[u >> 2] | 0;
-     if (!a) {
-      y = 0;
-      break;
-     } else {
-      z = a;
-      A = u;
-     }
-    } else {
-     z = p;
-     A = t;
-    }
-    while (1) {
-     t = z + 20 | 0;
-     p = k[t >> 2] | 0;
-     if (p | 0) {
-      z = p;
-      A = t;
-      continue;
-     }
-     t = z + 16 | 0;
-     p = k[t >> 2] | 0;
-     if (!p) {
-      B = z;
-      C = A;
-      break;
-     } else {
-      z = p;
-      A = t;
-     }
-    }
-    if (C >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-     k[C >> 2] = 0;
-     y = B;
-     break;
-    }
-   } else {
-    t = k[f + 8 >> 2] | 0;
-    if (t >>> 0 < (k[306] | 0) >>> 0) qa();
-    p = t + 12 | 0;
-    if ((k[p >> 2] | 0) != (f | 0)) qa();
-    u = w + 8 | 0;
-    if ((k[u >> 2] | 0) == (f | 0)) {
-     k[p >> 2] = w;
-     k[u >> 2] = t;
-     y = w;
-     break;
-    } else qa();
-   } while (0);
-   if (v | 0) {
-    w = k[f + 28 >> 2] | 0;
-    i = 1512 + (w << 2) | 0;
-    if ((f | 0) == (k[i >> 2] | 0)) {
-     k[i >> 2] = y;
-     if (!y) {
-      k[303] = k[303] & ~(1 << w);
-      break;
-     }
-    } else {
-     if (v >>> 0 < (k[306] | 0) >>> 0) qa();
-     w = v + 16 | 0;
-     if ((k[w >> 2] | 0) == (f | 0)) k[w >> 2] = y; else k[v + 20 >> 2] = y;
-     if (!y) break;
-    }
-    w = k[306] | 0;
-    if (y >>> 0 < w >>> 0) qa();
-    k[y + 24 >> 2] = v;
-    i = f + 16 | 0;
-    h = k[i >> 2] | 0;
-    do if (h | 0) if (h >>> 0 < w >>> 0) qa(); else {
-     k[y + 16 >> 2] = h;
-     k[h + 24 >> 2] = y;
-     break;
-    } while (0);
-    h = k[i + 4 >> 2] | 0;
-    if (h | 0) if (h >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-     k[y + 20 >> 2] = h;
-     k[h + 24 >> 2] = y;
-     break;
-    }
-   }
-  } while (0);
-  k[m + 4 >> 2] = s | 1;
-  k[m + s >> 2] = s;
-  if ((m | 0) == (k[307] | 0)) {
-   k[304] = s;
-   return;
-  } else D = s;
- } else {
-  k[e >> 2] = b & -2;
-  k[m + 4 >> 2] = n | 1;
-  k[m + n >> 2] = n;
-  D = n;
- }
- n = D >>> 3;
- if (D >>> 0 < 256) {
-  b = 1248 + (n << 1 << 2) | 0;
-  e = k[302] | 0;
-  s = 1 << n;
-  if (!(e & s)) {
-   k[302] = e | s;
-   E = b + 8 | 0;
-   F = b;
-  } else {
-   s = b + 8 | 0;
-   e = k[s >> 2] | 0;
-   if (e >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-    E = s;
-    F = e;
-   }
-  }
-  k[E >> 2] = m;
-  k[F + 12 >> 2] = m;
-  k[m + 8 >> 2] = F;
-  k[m + 12 >> 2] = b;
-  return;
- }
- b = D >>> 8;
- if (!b) G = 0; else if (D >>> 0 > 16777215) G = 31; else {
-  F = (b + 1048320 | 0) >>> 16 & 8;
-  E = b << F;
-  b = (E + 520192 | 0) >>> 16 & 4;
-  e = E << b;
-  E = (e + 245760 | 0) >>> 16 & 2;
-  s = 14 - (b | F | E) + (e << E >>> 15) | 0;
-  G = D >>> (s + 7 | 0) & 1 | s << 1;
- }
- s = 1512 + (G << 2) | 0;
- k[m + 28 >> 2] = G;
- k[m + 20 >> 2] = 0;
- k[m + 16 >> 2] = 0;
- E = k[303] | 0;
- e = 1 << G;
- do if (!(E & e)) {
-  k[303] = E | e;
-  k[s >> 2] = m;
-  k[m + 24 >> 2] = s;
-  k[m + 12 >> 2] = m;
-  k[m + 8 >> 2] = m;
- } else {
-  F = D << ((G | 0) == 31 ? 0 : 25 - (G >>> 1) | 0);
-  b = k[s >> 2] | 0;
-  while (1) {
-   if ((k[b + 4 >> 2] & -8 | 0) == (D | 0)) {
-    H = b;
-    I = 130;
-    break;
-   }
-   n = b + 16 + (F >>> 31 << 2) | 0;
-   y = k[n >> 2] | 0;
-   if (!y) {
-    J = n;
-    K = b;
-    I = 127;
-    break;
-   } else {
-    F = F << 1;
-    b = y;
-   }
-  }
-  if ((I | 0) == 127) if (J >>> 0 < (k[306] | 0) >>> 0) qa(); else {
-   k[J >> 2] = m;
-   k[m + 24 >> 2] = K;
-   k[m + 12 >> 2] = m;
-   k[m + 8 >> 2] = m;
-   break;
-  } else if ((I | 0) == 130) {
-   b = H + 8 | 0;
-   F = k[b >> 2] | 0;
-   i = k[306] | 0;
-   if (F >>> 0 >= i >>> 0 & H >>> 0 >= i >>> 0) {
-    k[F + 12 >> 2] = m;
-    k[b >> 2] = m;
-    k[m + 8 >> 2] = F;
-    k[m + 12 >> 2] = H;
-    k[m + 24 >> 2] = 0;
-    break;
-   } else qa();
-  }
- } while (0);
- m = (k[310] | 0) + -1 | 0;
- k[310] = m;
- if (!m) L = 1664; else return;
- while (1) {
-  m = k[L >> 2] | 0;
-  if (!m) break; else L = m + 8 | 0;
- }
- k[310] = -1;
- return;
-}
-
-function Ra(a, b, c) {
- a = a | 0;
- b = b | 0;
- c = c | 0;
- var d = 0, e = 0, f = 0, g = 0, h = 0, i = 0, j = 0, l = 0, m = 0, n = 0, o = 0, p = 0, q = 0, s = 0, t = 0, u = 0, v = 0, w = 0, x = 0, y = 0, z = 0;
- d = r;
- r = r + 48 | 0;
- e = d + 16 | 0;
- f = d;
- g = d + 32 | 0;
- h = a + 28 | 0;
- i = k[h >> 2] | 0;
- k[g >> 2] = i;
- j = a + 20 | 0;
- l = (k[j >> 2] | 0) - i | 0;
- k[g + 4 >> 2] = l;
- k[g + 8 >> 2] = b;
- k[g + 12 >> 2] = c;
- b = a + 60 | 0;
- i = a + 44 | 0;
- m = g;
- g = 2;
- n = l + c | 0;
- while (1) {
-  if (!(k[290] | 0)) {
-   k[e >> 2] = k[b >> 2];
-   k[e + 4 >> 2] = m;
-   k[e + 8 >> 2] = g;
-   o = Pa(ya(146, e | 0) | 0) | 0;
-  } else {
-   ra(1, a | 0);
-   k[f >> 2] = k[b >> 2];
-   k[f + 4 >> 2] = m;
-   k[f + 8 >> 2] = g;
-   l = Pa(ya(146, f | 0) | 0) | 0;
-   oa(0);
-   o = l;
-  }
-  if ((n | 0) == (o | 0)) {
-   p = 6;
-   break;
-  }
-  if ((o | 0) < 0) {
-   q = m;
-   s = g;
-   p = 8;
-   break;
-  }
-  l = n - o | 0;
-  t = k[m + 4 >> 2] | 0;
-  if (o >>> 0 > t >>> 0) {
-   u = k[i >> 2] | 0;
-   k[h >> 2] = u;
-   k[j >> 2] = u;
-   v = k[m + 12 >> 2] | 0;
-   w = o - t | 0;
-   x = m + 8 | 0;
-   y = g + -1 | 0;
-  } else if ((g | 0) == 2) {
-   k[h >> 2] = (k[h >> 2] | 0) + o;
-   v = t;
-   w = o;
-   x = m;
-   y = 2;
-  } else {
-   v = t;
-   w = o;
-   x = m;
-   y = g;
-  }
-  k[x >> 2] = (k[x >> 2] | 0) + w;
-  k[x + 4 >> 2] = v - w;
-  m = x;
-  g = y;
-  n = l;
- }
- if ((p | 0) == 6) {
-  n = k[i >> 2] | 0;
-  k[a + 16 >> 2] = n + (k[a + 48 >> 2] | 0);
-  i = n;
-  k[h >> 2] = i;
-  k[j >> 2] = i;
-  z = c;
- } else if ((p | 0) == 8) {
-  k[a + 16 >> 2] = 0;
-  k[h >> 2] = 0;
-  k[j >> 2] = 0;
-  k[a >> 2] = k[a >> 2] | 32;
-  if ((s | 0) == 2) z = 0; else z = c - (k[q + 4 >> 2] | 0) | 0;
- }
- r = d;
- return z | 0;
-}
-
-function Wa(a, b, c) {
- a = a | 0;
- b = b | 0;
- c = c | 0;
- var d = 0, e = 0, f = 0, g = 0, h = 0, j = 0, l = 0, m = 0, n = 0, o = 0, p = 0, q = 0;
- d = c + 16 | 0;
- e = k[d >> 2] | 0;
- if (!e) if (!(Xa(c) | 0)) {
-  f = k[d >> 2] | 0;
-  g = 5;
- } else h = 0; else {
-  f = e;
-  g = 5;
- }
- a : do if ((g | 0) == 5) {
-  e = c + 20 | 0;
-  d = k[e >> 2] | 0;
-  j = d;
-  if ((f - d | 0) >>> 0 < b >>> 0) {
-   h = Ca[k[c + 36 >> 2] & 3](c, a, b) | 0;
-   break;
-  }
-  b : do if ((i[c + 75 >> 0] | 0) > -1) {
-   d = b;
-   while (1) {
-    if (!d) {
-     l = b;
-     m = a;
-     n = j;
-     o = 0;
-     break b;
-    }
-    p = d + -1 | 0;
-    if ((i[a + p >> 0] | 0) == 10) {
-     q = d;
-     break;
-    } else d = p;
-   }
-   if ((Ca[k[c + 36 >> 2] & 3](c, a, q) | 0) >>> 0 < q >>> 0) {
-    h = q;
-    break a;
-   }
-   l = b - q | 0;
-   m = a + q | 0;
-   n = k[e >> 2] | 0;
-   o = q;
-  } else {
-   l = b;
-   m = a;
-   n = j;
-   o = 0;
-  } while (0);
-  jb(n | 0, m | 0, l | 0) | 0;
-  k[e >> 2] = (k[e >> 2] | 0) + l;
-  h = o + l | 0;
- } while (0);
- return h | 0;
-}
-
-function Za(a) {
- a = a | 0;
- var b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, j = 0, l = 0, m = 0;
- b = a;
- a : do if (!(b & 3)) {
-  c = a;
-  d = 4;
- } else {
-  e = a;
-  f = b;
-  while (1) {
-   if (!(i[e >> 0] | 0)) {
-    g = f;
-    break a;
-   }
-   h = e + 1 | 0;
-   f = h;
-   if (!(f & 3)) {
-    c = h;
-    d = 4;
-    break;
-   } else e = h;
-  }
- } while (0);
- if ((d | 0) == 4) {
-  d = c;
-  while (1) {
-   c = k[d >> 2] | 0;
-   if (!((c & -2139062144 ^ -2139062144) & c + -16843009)) d = d + 4 | 0; else {
-    j = c;
-    l = d;
-    break;
-   }
-  }
-  if (!((j & 255) << 24 >> 24)) m = l; else {
-   j = l;
-   while (1) {
-    l = j + 1 | 0;
-    if (!(i[l >> 0] | 0)) {
-     m = l;
-     break;
-    } else j = l;
-   }
-  }
-  g = m;
- }
- return g - b | 0;
-}
-
-function _a(a) {
- a = a | 0;
- var b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0;
- do if (!a) {
-  if (!(k[285] | 0)) b = 0; else b = _a(k[285] | 0) | 0;
-  pa(1188);
-  c = k[296] | 0;
-  if (!c) d = b; else {
-   e = c;
-   c = b;
-   while (1) {
-    if ((k[e + 76 >> 2] | 0) > -1) f = Ya(e) | 0; else f = 0;
-    if ((k[e + 20 >> 2] | 0) >>> 0 > (k[e + 28 >> 2] | 0) >>> 0) g = $a(e) | 0 | c; else g = c;
-    if (f | 0) Ta(e);
-    e = k[e + 56 >> 2] | 0;
-    if (!e) {
-     d = g;
-     break;
-    } else c = g;
-   }
-  }
-  xa(1188);
-  h = d;
- } else {
-  if ((k[a + 76 >> 2] | 0) <= -1) {
-   h = $a(a) | 0;
-   break;
-  }
-  c = (Ya(a) | 0) == 0;
-  e = $a(a) | 0;
-  if (c) h = e; else {
-   Ta(a);
-   h = e;
-  }
- } while (0);
- return h | 0;
-}
-
-function ab(a, b) {
- a = a | 0;
- b = b | 0;
- var c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, j = 0, m = 0, n = 0;
- c = r;
- r = r + 16 | 0;
- d = c;
- e = b & 255;
- i[d >> 0] = e;
- f = a + 16 | 0;
- g = k[f >> 2] | 0;
- if (!g) if (!(Xa(a) | 0)) {
-  h = k[f >> 2] | 0;
-  j = 4;
- } else m = -1; else {
-  h = g;
-  j = 4;
- }
- do if ((j | 0) == 4) {
-  g = a + 20 | 0;
-  f = k[g >> 2] | 0;
-  if (f >>> 0 < h >>> 0) {
-   n = b & 255;
-   if ((n | 0) != (i[a + 75 >> 0] | 0)) {
-    k[g >> 2] = f + 1;
-    i[f >> 0] = e;
-    m = n;
-    break;
-   }
-  }
-  if ((Ca[k[a + 36 >> 2] & 3](a, d, 1) | 0) == 1) m = l[d >> 0] | 0; else m = -1;
- } while (0);
- r = c;
- return m | 0;
-}
-
-function $a(a) {
- a = a | 0;
- var b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0;
- b = a + 20 | 0;
- c = a + 28 | 0;
- if ((k[b >> 2] | 0) >>> 0 > (k[c >> 2] | 0) >>> 0) {
-  Ca[k[a + 36 >> 2] & 3](a, 0, 0) | 0;
-  if (!(k[b >> 2] | 0)) d = -1; else e = 3;
- } else e = 3;
- if ((e | 0) == 3) {
-  e = a + 4 | 0;
-  f = k[e >> 2] | 0;
-  g = a + 8 | 0;
-  h = k[g >> 2] | 0;
-  if (f >>> 0 < h >>> 0) Ca[k[a + 40 >> 2] & 3](a, f - h | 0, 1) | 0;
-  k[a + 16 >> 2] = 0;
-  k[c >> 2] = 0;
-  k[b >> 2] = 0;
-  k[g >> 2] = 0;
-  k[e >> 2] = 0;
-  d = 0;
- }
- return d | 0;
-}
-
-function jb(a, b, c) {
- a = a | 0;
- b = b | 0;
- c = c | 0;
- var d = 0;
- if ((c | 0) >= 4096) return va(a | 0, b | 0, c | 0) | 0;
- d = a | 0;
- if ((a & 3) == (b & 3)) {
-  while (a & 3) {
-   if (!c) return d | 0;
-   i[a >> 0] = i[b >> 0] | 0;
-   a = a + 1 | 0;
-   b = b + 1 | 0;
-   c = c - 1 | 0;
-  }
-  while ((c | 0) >= 4) {
-   k[a >> 2] = k[b >> 2];
-   a = a + 4 | 0;
-   b = b + 4 | 0;
-   c = c - 4 | 0;
-  }
- }
- while ((c | 0) > 0) {
-  i[a >> 0] = i[b >> 0] | 0;
-  a = a + 1 | 0;
-  b = b + 1 | 0;
-  c = c - 1 | 0;
- }
- return d | 0;
-}
-
-function gb() {}
-function hb(a, b, c) {
- a = a | 0;
- b = b | 0;
- c = c | 0;
- var d = 0, e = 0, f = 0, g = 0;
- d = a + c | 0;
- if ((c | 0) >= 20) {
-  b = b & 255;
-  e = a & 3;
-  f = b | b << 8 | b << 16 | b << 24;
-  g = d & ~3;
-  if (e) {
-   e = a + 4 - e | 0;
-   while ((a | 0) < (e | 0)) {
-    i[a >> 0] = b;
-    a = a + 1 | 0;
-   }
-  }
-  while ((a | 0) < (g | 0)) {
-   k[a >> 2] = f;
-   a = a + 4 | 0;
-  }
- }
- while ((a | 0) < (d | 0)) {
-  i[a >> 0] = b;
-  a = a + 1 | 0;
- }
- return a - c | 0;
-}
-
-function db(a) {
- a = a | 0;
- var b = 0, c = 0, d = 0, e = 0, f = 0;
- b = k[256] | 0;
- if ((k[b + 76 >> 2] | 0) > -1) c = Ya(b) | 0; else c = 0;
- do if ((cb(a, b) | 0) < 0) d = 1; else {
-  if ((i[b + 75 >> 0] | 0) != 10) {
-   e = b + 20 | 0;
-   f = k[e >> 2] | 0;
-   if (f >>> 0 < (k[b + 16 >> 2] | 0) >>> 0) {
-    k[e >> 2] = f + 1;
-    i[f >> 0] = 10;
-    d = 0;
-    break;
-   }
-  }
-  d = (ab(b, 10) | 0) < 0;
- } while (0);
- if (c | 0) Ta(b);
- return d << 31 >> 31 | 0;
-}
-
-function Xa(a) {
- a = a | 0;
- var b = 0, c = 0, d = 0;
- b = a + 74 | 0;
- c = i[b >> 0] | 0;
- i[b >> 0] = c + 255 | c;
- c = k[a >> 2] | 0;
- if (!(c & 8)) {
-  k[a + 8 >> 2] = 0;
-  k[a + 4 >> 2] = 0;
-  b = k[a + 44 >> 2] | 0;
-  k[a + 28 >> 2] = b;
-  k[a + 20 >> 2] = b;
-  k[a + 16 >> 2] = b + (k[a + 48 >> 2] | 0);
-  d = 0;
- } else {
-  k[a >> 2] = c | 32;
-  d = -1;
- }
- return d | 0;
-}
-
-function bb(a, b, c, d) {
- a = a | 0;
- b = b | 0;
- c = c | 0;
- d = d | 0;
- var e = 0, f = 0, g = 0, h = 0, i = 0;
- e = ga(c, b) | 0;
- if ((k[d + 76 >> 2] | 0) > -1) {
-  f = (Ya(d) | 0) == 0;
-  g = Wa(a, e, d) | 0;
-  if (f) h = g; else {
-   Ta(d);
-   h = g;
-  }
- } else h = Wa(a, e, d) | 0;
- if ((h | 0) == (e | 0)) i = c; else i = (h >>> 0) / (b >>> 0) | 0;
- return i | 0;
-}
-
-function Ua(a, b, c) {
- a = a | 0;
- b = b | 0;
- c = c | 0;
- var d = 0, e = 0, f = 0, g = 0;
- d = r;
- r = r + 32 | 0;
- e = d;
- f = d + 20 | 0;
- k[e >> 2] = k[a + 60 >> 2];
- k[e + 4 >> 2] = 0;
- k[e + 8 >> 2] = b;
- k[e + 12 >> 2] = f;
- k[e + 16 >> 2] = c;
- if ((Pa(ua(140, e | 0) | 0) | 0) < 0) {
-  k[f >> 2] = -1;
-  g = -1;
- } else g = k[f >> 2] | 0;
- r = d;
- return g | 0;
-}
-
-function Va(a, b, c) {
- a = a | 0;
- b = b | 0;
- c = c | 0;
- var d = 0, e = 0;
- d = r;
- r = r + 80 | 0;
- e = d;
- k[a + 36 >> 2] = 3;
- if (!(k[a >> 2] & 64)) {
-  k[e >> 2] = k[a + 60 >> 2];
-  k[e + 4 >> 2] = 21505;
-  k[e + 8 >> 2] = d + 12;
-  if (wa(54, e | 0) | 0) i[a + 75 >> 0] = -1;
- }
- e = Ra(a, b, c) | 0;
- r = d;
- return e | 0;
-}
-
-function Ka(a) {
- a = a | 0;
- i[t >> 0] = i[a >> 0];
- i[t + 1 >> 0] = i[a + 1 >> 0];
- i[t + 2 >> 0] = i[a + 2 >> 0];
- i[t + 3 >> 0] = i[a + 3 >> 0];
- i[t + 4 >> 0] = i[a + 4 >> 0];
- i[t + 5 >> 0] = i[a + 5 >> 0];
- i[t + 6 >> 0] = i[a + 6 >> 0];
- i[t + 7 >> 0] = i[a + 7 >> 0];
-}
-
-function Oa(a) {
- a = a | 0;
- var b = 0, c = 0;
- b = r;
- r = r + 16 | 0;
- c = b;
- k[c >> 2] = k[a + 60 >> 2];
- a = Pa(sa(6, c | 0) | 0) | 0;
- r = b;
- return a | 0;
-}
-
-function Pa(a) {
- a = a | 0;
- var b = 0, c = 0;
- if (a >>> 0 > 4294963200) {
-  b = Qa() | 0;
-  k[b >> 2] = 0 - a;
-  c = -1;
- } else c = a;
- return c | 0;
-}
-
-function Ja(a) {
- a = a | 0;
- i[t >> 0] = i[a >> 0];
- i[t + 1 >> 0] = i[a + 1 >> 0];
- i[t + 2 >> 0] = i[a + 2 >> 0];
- i[t + 3 >> 0] = i[a + 3 >> 0];
-}
-
-function Qa() {
- var a = 0, b = 0;
- if (!(k[290] | 0)) a = 1204; else {
-  b = (ib() | 0) + 64 | 0;
-  a = k[b >> 2] | 0;
- }
- return a | 0;
-}
-
-function lb(a, b, c, d) {
- a = a | 0;
- b = b | 0;
- c = c | 0;
- d = d | 0;
- return Ca[a & 3](b | 0, c | 0, d | 0) | 0;
-}
-function Ea(a) {
- a = a | 0;
- var b = 0;
- b = r;
- r = r + a | 0;
- r = r + 15 & -16;
- return b | 0;
-}
-
-function cb(a, b) {
- a = a | 0;
- b = b | 0;
- return (bb(a, Za(a) | 0, 1, b) | 0) + -1 | 0;
-}
-
-function ob(a, b, c) {
- a = a | 0;
- b = b | 0;
- c = c | 0;
- ja(1);
- return 0;
-}
-
-function Ia(a, b) {
- a = a | 0;
- b = b | 0;
- if (!v) {
-  v = a;
-  w = b;
- }
-}
-
-function kb(a, b) {
- a = a | 0;
- b = b | 0;
- return Ba[a & 1](b | 0) | 0;
-}
-
-function Sa(a) {
- a = a | 0;
- if (!(k[a + 68 >> 2] | 0)) Ta(a);
- return;
-}
-
-function mb(a, b) {
- a = a | 0;
- b = b | 0;
- Da[a & 1](b | 0);
-}
-
-function Ha(a, b) {
- a = a | 0;
- b = b | 0;
- r = a;
- s = b;
-}
-
-function nb(a) {
- a = a | 0;
- ja(0);
- return 0;
-}
-
-function Na() {
- db(1144) | 0;
- return 0;
-}
-
-function Ya(a) {
- a = a | 0;
- return 0;
-}
-
-function Ta(a) {
- a = a | 0;
- return;
-}
-
-function pb(a) {
- a = a | 0;
- ja(2);
-}
-
-function La(a) {
- a = a | 0;
- K = a;
-}
-
-function Ga(a) {
- a = a | 0;
- r = a;
-}
-
-function Ma() {
- return K | 0;
-}
-
-function Fa() {
- return r | 0;
-}
-
-function ib() {
- return 0;
-}
-
-// EMSCRIPTEN_END_FUNCS
-
- var Ba = [ nb, Oa ];
- var Ca = [ ob, Va, Ua, Ra ];
- var Da = [ pb, Sa ];
- return {
-  _free: fb,
-  _main: Na,
-  _pthread_self: ib,
-  _memset: hb,
-  _malloc: eb,
-  _memcpy: jb,
-  _fflush: _a,
-  ___errno_location: Qa,
-  runPostSets: gb,
-  _emscripten_replace_memory: Aa,
-  stackAlloc: Ea,
-  stackSave: Fa,
-  stackRestore: Ga,
-  establishStackSpace: Ha,
-  setThrew: Ia,
-  setTempRet0: La,
-  getTempRet0: Ma,
-  dynCall_ii: kb,
-  dynCall_iiii: lb,
-  dynCall_vi: mb
- };
-})
-
-
-;
diff --git a/binaryen/test/metadce/outside.wast b/binaryen/test/metadce/outside.wast
--- a/binaryen/test/metadce/outside.wast
+++ b/binaryen/test/metadce/outside.wast
@@ -1,8 +1,6 @@
 (module
  (import "env" "js_func" (func $a_js_func))
  (import "env" "js_func_unused" (func $an_unused_js_func))
- (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR$asm2wasm$import i32))
- (import "env" "DYNAMICTOP_PTR_unused" (global $DYNAMICTOP_PTR$asm2wasm$import_unused i32))
  (import "env" "memory" (memory $0 256 256))
  (import "env" "table" (table 10 10 funcref))
 
@@ -21,11 +19,9 @@
 
  (func $a_wasm_func
   (call $a_js_func)
-  (drop (global.get $DYNAMICTOP_PTR$asm2wasm$import))
   (drop (global.get $__THREW__))
  )
  (func $an_unused_wasm_func
-  (drop (global.get $DYNAMICTOP_PTR$asm2wasm$import_unused))
   (drop (global.get $__THREW__unused))
  )
  (func $table_func
diff --git a/binaryen/test/metadce/outside.wast.dced b/binaryen/test/metadce/outside.wast.dced
--- a/binaryen/test/metadce/outside.wast.dced
+++ b/binaryen/test/metadce/outside.wast.dced
@@ -5,7 +5,6 @@
  (data (global.get $from_segment) "abcd")
  (import "env" "table" (table $timport$0 10 10 funcref))
  (elem (global.get $from_segment_2) $table_func)
- (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR$asm2wasm$import i32))
  (import "env" "js_func" (func $a_js_func))
  (global $__THREW__ (mut i32) (i32.const 0))
  (global $from_segment (mut i32) (i32.const 0))
@@ -16,9 +15,6 @@
  )
  (func $a_wasm_func
   (call $a_js_func)
-  (drop
-   (global.get $DYNAMICTOP_PTR$asm2wasm$import)
-  )
   (drop
    (global.get $__THREW__)
   )
diff --git a/binaryen/test/metadce/outside.wast.dced.stdout b/binaryen/test/metadce/outside.wast.dced.stdout
--- a/binaryen/test/metadce/outside.wast.dced.stdout
+++ b/binaryen/test/metadce/outside.wast.dced.stdout
@@ -1,4 +1,4 @@
-unused: export$wasm_func_unused$12
+unused: export$wasm_func_unused$10
 unused: func$an_unused_wasm_func$1
 unused: global$__THREW__unused$4
 unused: global$from_segment$5
diff --git a/binaryen/test/min.asm.js b/binaryen/test/min.asm.js
deleted file mode 100644
--- a/binaryen/test/min.asm.js
+++ /dev/null
@@ -1,52 +0,0 @@
-function (global, env, buffer) {
-  "use asm";
-
-  var c = new global.Int32Array(buffer);
-  var g = new global.Float32Array(buffer);
-
-  var fr = global.Math.fround;
-
-  var tDP = env.tempDoublePtr | 0;
-  var ctz32 = env._llvm_cttz_i32;
-
-  var h8 = new global.Int8Array(buffer);
-  var h16 = new global.Int16Array(buffer);
-  var h32 = new global.Int32Array(buffer);
-  var hU8 = new global.Uint8Array(buffer);
-  var hU16 = new global.Uint16Array(buffer);
-  var hU32 = new global.Uint32Array(buffer);
-  var hF32 = new global.Float32Array(buffer);
-  var hF64 = new global.Float64Array(buffer);
-
-  var M = 0; // tempRet
-
-  function floats(f) {
-    f = fr(f);
-    var t = fr(0);
-    return fr(t + f);
-  }
-  function neg(k, p) {
-    k = k | 0;
-    p = p | 0;
-    var n = fr(0);
-    n = fr(-(c[k >> 2] = p, fr(g[k >> 2])));
-    return n;
-  }
-  function bitcasts(i, f) {
-    i = i | 0;
-    f = Math_fround(f);
-    (h32[tDP >> 2] = i, fr(hF32[tDP >> 2])); // i32->f32
-    (h32[tDP >> 2] = i, +hF32[tDP >> 2]); // i32->f32, no fround
-    (hF32[tDP >> 2] = f, h32[tDP >> 2] | 0); // f32->i32
-  }
-  function ctzzzz() {
-    return ctz32(0x1234) | 0;
-  }
-  function ub() {
-    ub(); // emterpreter assertions mode might add some code here
-    return M | 0;
-  }
-
-  return { floats: floats, getTempRet0: ub, neg: neg, bitcasts: bitcasts, ctzzzz: ctzzzz };
-}
-
diff --git a/binaryen/test/min.wast.from-wast b/binaryen/test/min.wast.from-wast
--- a/binaryen/test/min.wast.from-wast
+++ b/binaryen/test/min.wast.from-wast
@@ -1,8 +1,8 @@
 (module
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
- (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
  (type $f32_=>_f32 (func (param f32) (result f32)))
+ (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
  (memory $0 256 256)
  (export "floats" (func $floats))
  (func $floats (param $f f32) (result f32)
diff --git a/binaryen/test/min.wast.fromBinary b/binaryen/test/min.wast.fromBinary
--- a/binaryen/test/min.wast.fromBinary
+++ b/binaryen/test/min.wast.fromBinary
@@ -1,8 +1,8 @@
 (module
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
- (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
  (type $f32_=>_f32 (func (param f32) (result f32)))
+ (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
  (memory $0 256 256)
  (export "floats" (func $floats))
  (func $floats (param $f f32) (result f32)
diff --git a/binaryen/test/min.wast.fromBinary.noDebugInfo b/binaryen/test/min.wast.fromBinary.noDebugInfo
--- a/binaryen/test/min.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/min.wast.fromBinary.noDebugInfo
@@ -1,8 +1,8 @@
 (module
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
- (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
  (type $f32_=>_f32 (func (param f32) (result f32)))
+ (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
  (memory $0 256 256)
  (export "floats" (func $0))
  (func $0 (param $0 f32) (result f32)
diff --git a/binaryen/test/multivalue.wast.from-wast b/binaryen/test/multivalue.wast.from-wast
--- a/binaryen/test/multivalue.wast.from-wast
+++ b/binaryen/test/multivalue.wast.from-wast
@@ -1,12 +1,12 @@
 (module
  (type $none_=>_i32_i64 (func (result i32 i64)))
  (type $none_=>_none (func))
- (type $none_=>_i32_i64_externref (func (result i32 i64 externref)))
  (type $none_=>_i64 (func (result i64)))
+ (type $none_=>_i32_i64_externref (func (result i32 i64 externref)))
  (type $none_=>_f32_i64_i32 (func (result f32 i64 i32)))
  (type $none_=>_i32 (func (result i32)))
- (type $none_=>_i32_i64_f32 (func (result i32 i64 f32)))
  (type $none_=>_f32 (func (result f32)))
+ (type $none_=>_i32_i64_f32 (func (result i32 i64 f32)))
  (import "env" "pair" (func $pair (result i32 i64)))
  (global $g1 (mut (i32 i64)) (tuple.make
   (i32.const 0)
diff --git a/binaryen/test/multivalue.wast.fromBinary b/binaryen/test/multivalue.wast.fromBinary
--- a/binaryen/test/multivalue.wast.fromBinary
+++ b/binaryen/test/multivalue.wast.fromBinary
@@ -5,8 +5,8 @@
  (type $none_=>_i64 (func (result i64)))
  (type $none_=>_f32_i64_i32 (func (result f32 i64 i32)))
  (type $none_=>_i32 (func (result i32)))
- (type $none_=>_i32_i64_f32 (func (result i32 i64 f32)))
  (type $none_=>_f32 (func (result f32)))
+ (type $none_=>_i32_i64_f32 (func (result i32 i64 f32)))
  (import "env" "pair" (func $pair (result i32 i64)))
  (global $g1 (mut i32) (i32.const 0))
  (global $g2 (mut i64) (i64.const 0))
diff --git a/binaryen/test/multivalue.wast.fromBinary.noDebugInfo b/binaryen/test/multivalue.wast.fromBinary.noDebugInfo
--- a/binaryen/test/multivalue.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/multivalue.wast.fromBinary.noDebugInfo
@@ -5,8 +5,8 @@
  (type $none_=>_i64 (func (result i64)))
  (type $none_=>_f32_i64_i32 (func (result f32 i64 i32)))
  (type $none_=>_i32 (func (result i32)))
- (type $none_=>_i32_i64_f32 (func (result i32 i64 f32)))
  (type $none_=>_f32 (func (result f32)))
+ (type $none_=>_i32_i64_f32 (func (result i32 i64 f32)))
  (import "env" "pair" (func $fimport$0 (result i32 i64)))
  (global $global$0 (mut i32) (i32.const 0))
  (global $global$1 (mut i64) (i64.const 0))
diff --git a/binaryen/test/noffi_f32.asm.js b/binaryen/test/noffi_f32.asm.js
deleted file mode 100644
--- a/binaryen/test/noffi_f32.asm.js
+++ /dev/null
@@ -1,21 +0,0 @@
-function(global, env, buffer) {
-    "use asm";
-    var Math_fround=global.Math.fround;
-    var importf=env._importf;
-
-    function exportf(a){
-        a=Math_fround(a);
-        return Math_fround(a+Math_fround(1.0))
-    }
-    function main(){
-        Math_fround(importf(Math_fround(3.4000000953674316)));
-        return 0
-    }
-
-    return{
-        main:main,
-        exportf:exportf}
-}
-
-;
-
diff --git a/binaryen/test/noffi_i64.asm.js b/binaryen/test/noffi_i64.asm.js
deleted file mode 100644
--- a/binaryen/test/noffi_i64.asm.js
+++ /dev/null
@@ -1,21 +0,0 @@
-function(global, env, buffer) {
-  "use asm";
-  var importll=env._importll;
-
-  function add(a,b) {
-      a = i64(a);
-      b = i64(b);
-      var c = i64();
-      c = i64_add(b,a);
-      return (i64(c));
-  }
-  function main() {
-      (i64(importll(i64_const(2,0))));
-      return 0;
-  }
-
-  return {
-      _add: add,
-      _main: main };
-}
-;
diff --git a/binaryen/test/passes/O.bin.txt b/binaryen/test/passes/O.bin.txt
--- a/binaryen/test/passes/O.bin.txt
+++ b/binaryen/test/passes/O.bin.txt
@@ -93,9 +93,9 @@
     (br_if $label$3
      (i64.gt_s
       (local.tee $0
-       (i64.add
+       (i64.sub
         (local.get $0)
-        (i64.const -1)
+        (i64.const 1)
        )
       )
       (i64.const 1)
diff --git a/binaryen/test/passes/O3_inlining.txt b/binaryen/test/passes/O3_inlining.txt
--- a/binaryen/test/passes/O3_inlining.txt
+++ b/binaryen/test/passes/O3_inlining.txt
@@ -13,12 +13,8 @@
   )
   (if
    (i32.eqz
-    (if (result i32)
-     (i32.load16_u
-      (i32.const 3)
-     )
-     (i32.const 1)
-     (i32.const 0)
+    (i32.load16_u
+     (i32.const 3)
     )
    )
    (unreachable)
diff --git a/binaryen/test/passes/O3_low-memory-unused_metrics.txt b/binaryen/test/passes/O3_low-memory-unused_metrics.txt
--- a/binaryen/test/passes/O3_low-memory-unused_metrics.txt
+++ b/binaryen/test/passes/O3_low-memory-unused_metrics.txt
@@ -799,14 +799,14 @@
                    )
                   )
                   (local.set $5
-                   (i32.add
+                   (i32.sub
                     (i32.shl
                      (i32.load offset=48
                       (local.get $2)
                      )
                      (i32.const 12)
                     )
-                    (i32.const -30720)
+                    (i32.const 30720)
                    )
                   )
                   (local.set $3
@@ -1142,9 +1142,9 @@
                             )
                            )
                           )
-                          (i32.gt_u
-                           (local.get $5)
+                          (i32.lt_u
                            (local.get $3)
+                           (local.get $5)
                           )
                          )
                         )
@@ -1287,8 +1287,7 @@
                     )
                    )
                    (if
-                    (i32.ge_u
-                     (local.get $6)
+                    (i32.le_u
                      (i32.load16_u offset=20
                       (local.tee $5
                        (i32.load offset=28
@@ -1296,6 +1295,7 @@
                        )
                       )
                      )
+                     (local.get $6)
                     )
                     (block
                      (local.set $3
@@ -1482,9 +1482,9 @@
                           )
                          )
                         )
-                        (i32.gt_u
-                         (local.get $5)
+                        (i32.lt_u
                          (local.get $3)
+                         (local.get $5)
                         )
                        )
                       )
@@ -1795,9 +1795,9 @@
                       )
                      )
                     )
-                    (i32.gt_u
-                     (local.get $5)
+                    (i32.lt_u
                      (local.get $3)
+                     (local.get $5)
                     )
                    )
                   )
@@ -2030,16 +2030,16 @@
        (block
         (block $label$52
          (br_if $label$52
-          (i32.le_u
+          (i32.ge_u
+           (i32.load offset=12
+            (local.get $2)
+           )
            (i32.add
             (i32.load offset=20
              (local.get $2)
             )
             (i32.const 2)
            )
-           (i32.load offset=12
-            (local.get $2)
-           )
           )
          )
          (br_if $label$52
@@ -2060,9 +2060,9 @@
                )
               )
              )
-             (i32.gt_u
-              (local.get $5)
+             (i32.lt_u
               (local.get $3)
+              (local.get $5)
              )
             )
            )
@@ -2141,7 +2141,10 @@
          )
         )
         (br_if $label$6
-         (i32.gt_u
+         (i32.lt_u
+          (i32.load offset=12
+           (local.get $2)
+          )
           (i32.add
            (local.tee $3
             (i32.load offset=20
@@ -2150,9 +2153,6 @@
            )
            (i32.const 2)
           )
-          (i32.load offset=12
-           (local.get $2)
-          )
          )
         )
         (local.set $4
@@ -2344,9 +2344,9 @@
        )
       )
       (br_if $label$53
-       (i32.lt_s
-        (local.get $7)
+       (i32.gt_s
         (local.get $1)
+        (local.get $7)
        )
       )
       (br_if $label$53
@@ -2534,14 +2534,14 @@
           )
          )
          (local.tee $4
-          (i32.add
+          (i32.sub
            (i32.shl
             (i32.load offset=76
              (local.get $2)
             )
             (i32.const 1)
            )
-           (i32.const -2)
+           (i32.const 2)
           )
          )
         )
@@ -3024,9 +3024,9 @@
             )
            )
           )
-          (i32.gt_u
-           (local.get $4)
+          (i32.lt_u
            (local.get $1)
+           (local.get $4)
           )
          )
         )
diff --git a/binaryen/test/passes/O4_disable-bulk-memory.txt b/binaryen/test/passes/O4_disable-bulk-memory.txt
--- a/binaryen/test/passes/O4_disable-bulk-memory.txt
+++ b/binaryen/test/passes/O4_disable-bulk-memory.txt
@@ -14,8 +14,8 @@
  (type $none_=>_f64 (func (result f64)))
  (type $i32_=>_f64 (func (param i32) (result f64)))
  (import "env" "memory" (memory $1 1))
- (data (i32.const 8) "\0d\00\00\00~\00l\00i\00b\00/\00a\00r\00r\00a\00y\00.\00t\00s")
- (data (i32.const 40) "\1c\00\00\00~\00l\00i\00b\00/\00i\00n\00t\00e\00r\00n\00a\00l\00/\00a\00r\00r\00a\00y\00b\00u\00f\00f\00e\00r\00.\00t\00s")
+ (data (i32.const 8) "\0d\00\00\00~\00l\00i\00b\00/\00a\00r\00r\00a\00y\00.\00t\00s\00")
+ (data (i32.const 40) "\1c\00\00\00~\00l\00i\00b\00/\00i\00n\00t\00e\00r\00n\00a\00l\00/\00a\00r\00r\00a\00y\00b\00u\00f\00f\00e\00r\00.\00t\00s\00")
  (table $0 1 funcref)
  (elem (i32.const 0) $null)
  (global $global$0 (mut i32) (i32.const 0))
@@ -196,18 +196,15 @@
   (f64.store offset=24
    (local.tee $1
     (if (result i32)
-     (i32.lt_u
-      (i32.const 0)
-      (i32.shr_u
-       (i32.load
-        (local.tee $1
-         (i32.load
-          (local.get $0)
-         )
+     (i32.shr_u
+      (i32.load
+       (local.tee $1
+        (i32.load
+         (local.get $0)
         )
        )
-       (i32.const 2)
       )
+      (i32.const 2)
      )
      (i32.load offset=8
       (local.get $1)
@@ -216,28 +213,22 @@
     )
    )
    (f64.div
-    (f64.neg
-     (local.get $4)
-    )
-    (f64.const 39.47841760435743)
+    (local.get $4)
+    (f64.const -39.47841760435743)
    )
   )
   (f64.store offset=32
    (local.get $1)
    (f64.div
-    (f64.neg
-     (local.get $5)
-    )
-    (f64.const 39.47841760435743)
+    (local.get $5)
+    (f64.const -39.47841760435743)
    )
   )
   (f64.store offset=40
    (local.get $1)
    (f64.div
-    (f64.neg
-     (local.get $6)
-    )
-    (f64.const 39.47841760435743)
+    (local.get $6)
+    (f64.const -39.47841760435743)
    )
   )
   (i32.store
@@ -1218,9 +1209,9 @@
   (block $label$1
    (loop $label$2
     (br_if $label$1
-     (i32.ge_u
-      (local.get $1)
+     (i32.le_u
       (local.get $0)
+      (local.get $1)
      )
     )
     (call $assembly/index/NBodySystem#advance
@@ -1239,8 +1230,7 @@
  (func $assembly/index/getBody (; has Stack IR ;) (param $0 i32) (result i32)
   (local $1 i32)
   (if (result i32)
-   (i32.lt_u
-    (local.get $0)
+   (i32.gt_u
     (i32.load offset=4
      (local.tee $1
       (i32.load
@@ -1248,10 +1238,10 @@
       )
      )
     )
+    (local.get $0)
    )
    (if (result i32)
-    (i32.lt_u
-     (local.get $0)
+    (i32.gt_u
      (i32.shr_u
       (i32.load
        (local.tee $1
@@ -1262,6 +1252,7 @@
       )
       (i32.const 2)
      )
+     (local.get $0)
     )
     (i32.load offset=8
      (i32.add
diff --git a/binaryen/test/passes/O_all-features.txt b/binaryen/test/passes/O_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O_all-features.txt
@@ -0,0 +1,12 @@
+(module
+ (type ${i32} (struct (field i32)))
+ (type $ref?|{i32}|_=>_none (func (param (ref null ${i32}))))
+ (export "foo" (func $0))
+ (func $0 (; has Stack IR ;) (param $0 (ref null ${i32}))
+  (drop
+   (struct.get ${i32} 0
+    (local.get $0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/O_all-features.wast b/binaryen/test/passes/O_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O_all-features.wast
@@ -0,0 +1,16 @@
+;; Test that we can run GC types through the optimizer
+(module
+  (type $struct.A (struct i32))
+
+  (func "foo" (param $x (ref null $struct.A))
+    ;; get a struct reference
+    (drop
+      (local.get $x)
+    )
+    ;; get a struct field value
+    ;; (note that since this is a nullable reference, it may trap)
+    (drop
+      (struct.get $struct.A 0 (local.get $x))
+    )
+  )
+)
diff --git a/binaryen/test/passes/O_all-features_ignore-implicit-traps.txt b/binaryen/test/passes/O_all-features_ignore-implicit-traps.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O_all-features_ignore-implicit-traps.txt
@@ -0,0 +1,8 @@
+(module
+ (type ${i32} (struct (field i32)))
+ (type $ref?|{i32}|_=>_none (func (param (ref null ${i32}))))
+ (export "foo" (func $0))
+ (func $0 (; has Stack IR ;) (param $0 (ref null ${i32}))
+  (nop)
+ )
+)
diff --git a/binaryen/test/passes/O_all-features_ignore-implicit-traps.wast b/binaryen/test/passes/O_all-features_ignore-implicit-traps.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/O_all-features_ignore-implicit-traps.wast
@@ -0,0 +1,17 @@
+;; Test that we can run GC types through the optimizer
+(module
+  (type $struct.A (struct i32))
+
+  (func "foo" (param $x (ref null $struct.A))
+    ;; get a struct reference
+    (drop
+      (local.get $x)
+    )
+    ;; get a struct field value
+    ;; (note that since this is a nullable reference, it may trap, but we
+    ;; are ignoring implicit traps, so it has no side effects)
+    (drop
+      (struct.get $struct.A 0 (local.get $x))
+    )
+  )
+)
diff --git a/binaryen/test/passes/O_fast-math.txt b/binaryen/test/passes/O_fast-math.txt
--- a/binaryen/test/passes/O_fast-math.txt
+++ b/binaryen/test/passes/O_fast-math.txt
@@ -13,6 +13,8 @@
  (export "sub2" (func $2))
  (export "mul_neg_one1" (func $9))
  (export "mul_neg_one2" (func $10))
+ (export "abs_sub_zero1" (func $11))
+ (export "abs_sub_zero2" (func $12))
  (func $0 (; has Stack IR ;) (result f32)
   (f32.const -nan:0x23017a)
  )
@@ -20,7 +22,7 @@
   (f32.const -nan:0x34546d)
  )
  (func $2 (; has Stack IR ;) (result f32)
-  (f32.const -nan:0x74546d)
+  (f32.const nan:0x400000)
  )
  (func $9 (; has Stack IR ;) (param $0 f32) (result f32)
   (f32.neg
@@ -29,6 +31,16 @@
  )
  (func $10 (; has Stack IR ;) (param $0 f64) (result f64)
   (f64.neg
+   (local.get $0)
+  )
+ )
+ (func $11 (; has Stack IR ;) (param $0 f32) (result f32)
+  (f32.abs
+   (local.get $0)
+  )
+ )
+ (func $12 (; has Stack IR ;) (param $0 f64) (result f64)
+  (f64.abs
    (local.get $0)
   )
  )
diff --git a/binaryen/test/passes/O_fast-math.wast b/binaryen/test/passes/O_fast-math.wast
--- a/binaryen/test/passes/O_fast-math.wast
+++ b/binaryen/test/passes/O_fast-math.wast
@@ -66,4 +66,22 @@
    (f64.const -1)
   )
  )
+ (func "abs_sub_zero1" (param $x f32) (result f32)
+  ;; abs(0 - x)   ==>   abs(x)
+  (f32.abs
+   (f32.sub
+    (f32.const 0)
+    (local.get $x)
+   )
+  )
+ )
+ (func "abs_sub_zero2" (param $x f64) (result f64)
+  ;; abs(0 - x)   ==>   abs(x)
+  (f64.abs
+   (f64.sub
+    (f64.const 0)
+    (local.get $x)
+   )
+  )
+ )
 )
diff --git a/binaryen/test/passes/Os_print-stack-ir_all-features.txt b/binaryen/test/passes/Os_print-stack-ir_all-features.txt
--- a/binaryen/test/passes/Os_print-stack-ir_all-features.txt
+++ b/binaryen/test/passes/Os_print-stack-ir_all-features.txt
@@ -39,57 +39,3 @@
   )
  )
 )
-(module
- (type $none_=>_i32 (func (result i32)))
- (type $none_=>_i32_f64 (func (result i32 f64)))
- (type $none_=>_i64 (func (result i64)))
- (type $none_=>_f32 (func (result f32)))
- (type $none_=>_f64 (func (result f64)))
- (export "ppi32" (func $0))
- (export "ppi64" (func $1))
- (export "ppf32" (func $2))
- (export "ppf64" (func $3))
- (export "pair" (func $4))
- (func $0 (result i32)
-  
- )
- (func $1 (result i64)
-  
- )
- (func $2 (result f32)
-  
- )
- (func $3 (result f64)
-  
- )
- (func $4 (result i32 f64)
-  
- )
-)
-(module
- (type $none_=>_i32 (func (result i32)))
- (type $none_=>_i32_f64 (func (result i32 f64)))
- (type $none_=>_i64 (func (result i64)))
- (type $none_=>_f32 (func (result f32)))
- (type $none_=>_f64 (func (result f64)))
- (export "ppi32" (func $0))
- (export "ppi64" (func $1))
- (export "ppf32" (func $2))
- (export "ppf64" (func $3))
- (export "pair" (func $4))
- (func $0 (; has Stack IR ;) (result i32)
-  (pop i32)
- )
- (func $1 (; has Stack IR ;) (result i64)
-  (pop i64)
- )
- (func $2 (; has Stack IR ;) (result f32)
-  (pop f32)
- )
- (func $3 (; has Stack IR ;) (result f64)
-  (pop f64)
- )
- (func $4 (; has Stack IR ;) (result i32 f64)
-  (pop i32 f64)
- )
-)
diff --git a/binaryen/test/passes/Os_print-stack-ir_all-features.wast b/binaryen/test/passes/Os_print-stack-ir_all-features.wast
--- a/binaryen/test/passes/Os_print-stack-ir_all-features.wast
+++ b/binaryen/test/passes/Os_print-stack-ir_all-features.wast
@@ -14,23 +14,3 @@
   )
  )
 )
-(module
-  ;; These are not valid usages of pops - they are not meant to be
-  ;; used alone. This just tests we can emit them/handle them in the
-  ;; optimizer.
-  (func "ppi32" (result i32)
-    (pop i32)
-  )
-  (func "ppi64" (result i64)
-    (pop i64)
-  )
-  (func "ppf32" (result f32)
-    (pop f32)
-  )
-  (func "ppf64" (result f64)
-    (pop f64)
-  )
-  (func "pair" (result i32 f64)
-    (pop i32 f64)
-  )
-)
diff --git a/binaryen/test/passes/Oz_fuzz-exec_all-features.txt b/binaryen/test/passes/Oz_fuzz-exec_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/Oz_fuzz-exec_all-features.txt
@@ -0,0 +1,220 @@
+[fuzz-exec] calling structs
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 42]
+[LoggingExternalInterface logging 100]
+[LoggingExternalInterface logging 100]
+[fuzz-exec] calling arrays
+[LoggingExternalInterface logging 50]
+[LoggingExternalInterface logging 42]
+[LoggingExternalInterface logging 128]
+[LoggingExternalInterface logging -128]
+[LoggingExternalInterface logging 42]
+[fuzz-exec] calling rtts
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 1]
+[fuzz-exec] calling br_on_cast
+[LoggingExternalInterface logging 3]
+[trap unreachable]
+(module
+ (type ${i32} (struct (field i32)))
+ (type $none_=>_none (func))
+ (type ${i32_f64} (struct (field i32) (field f64)))
+ (type $[mut:i8] (array (mut i8)))
+ (type $i32_=>_none (func (param i32)))
+ (import "fuzzing-support" "log-i32" (func $log (param i32)))
+ (export "structs" (func $0))
+ (export "arrays" (func $1))
+ (export "rtts" (func $2))
+ (export "br_on_cast" (func $3))
+ (func $0 (; has Stack IR ;)
+  (local $0 (ref null ${i32}))
+  (call $log
+   (struct.get ${i32} 0
+    (local.tee $0
+     (struct.new_default_with_rtt ${i32}
+      (rtt.canon ${i32})
+     )
+    )
+   )
+  )
+  (struct.set ${i32} 0
+   (local.get $0)
+   (i32.const 42)
+  )
+  (call $log
+   (struct.get ${i32} 0
+    (local.get $0)
+   )
+  )
+  (struct.set ${i32} 0
+   (local.get $0)
+   (i32.const 100)
+  )
+  (call $log
+   (struct.get ${i32} 0
+    (local.get $0)
+   )
+  )
+  (call $log
+   (struct.get ${i32} 0
+    (local.get $0)
+   )
+  )
+ )
+ (func $1 (; has Stack IR ;)
+  (local $0 (ref null $[mut:i8]))
+  (call $log
+   (array.len $[mut:i8]
+    (local.tee $0
+     (array.new_with_rtt $[mut:i8]
+      (rtt.canon $[mut:i8])
+      (i32.const 50)
+      (i32.const 42)
+     )
+    )
+   )
+  )
+  (call $log
+   (array.get_u $[mut:i8]
+    (local.get $0)
+    (i32.const 10)
+   )
+  )
+  (array.set $[mut:i8]
+   (local.get $0)
+   (i32.const 10)
+   (i32.const 65408)
+  )
+  (call $log
+   (array.get_u $[mut:i8]
+    (local.get $0)
+    (i32.const 10)
+   )
+  )
+  (call $log
+   (array.get_s $[mut:i8]
+    (local.get $0)
+    (i32.const 10)
+   )
+  )
+  (call $log
+   (array.get_s $[mut:i8]
+    (local.get $0)
+    (i32.const 20)
+   )
+  )
+ )
+ (func $2 (; has Stack IR ;)
+  (local $0 (rtt ${i32}))
+  (local $1 (rtt ${i32_f64}))
+  (local $2 (rtt ${i32_f64}))
+  (local $3 anyref)
+  (local.set $1
+   (rtt.sub ${i32_f64}
+    (local.tee $0
+     (rtt.canon ${i32})
+    )
+   )
+  )
+  (local.set $2
+   (rtt.canon ${i32_f64})
+  )
+  (call $log
+   (ref.is_null
+    (ref.cast ${i32}
+     (ref.null ${i32})
+     (local.get $0)
+    )
+   )
+  )
+  (call $log
+   (ref.test ${i32}
+    (ref.null ${i32})
+    (local.get $0)
+   )
+  )
+  (call $log
+   (ref.test ${i32}
+    (array.new_with_rtt $[mut:i8]
+     (rtt.canon $[mut:i8])
+     (i32.const 10)
+     (i32.const 20)
+    )
+    (local.get $0)
+   )
+  )
+  (call $log
+   (ref.test ${i32}
+    (struct.new_default_with_rtt ${i32}
+     (local.get $0)
+    )
+    (local.get $0)
+   )
+  )
+  (call $log
+   (ref.test ${i32_f64}
+    (struct.new_default_with_rtt ${i32}
+     (local.get $0)
+    )
+    (local.get $2)
+   )
+  )
+  (call $log
+   (ref.test ${i32_f64}
+    (local.tee $3
+     (struct.new_default_with_rtt ${i32_f64}
+      (local.get $1)
+     )
+    )
+    (local.get $1)
+   )
+  )
+  (call $log
+   (ref.test ${i32_f64}
+    (local.get $3)
+    (local.get $2)
+   )
+  )
+  (call $log
+   (ref.test ${i32}
+    (local.get $3)
+    (local.get $0)
+   )
+  )
+ )
+ (func $3 (; has Stack IR ;)
+  (call $log
+   (i32.const 3)
+  )
+  (unreachable)
+ )
+)
+[fuzz-exec] calling structs
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 42]
+[LoggingExternalInterface logging 100]
+[LoggingExternalInterface logging 100]
+[fuzz-exec] calling arrays
+[LoggingExternalInterface logging 50]
+[LoggingExternalInterface logging 42]
+[LoggingExternalInterface logging 128]
+[LoggingExternalInterface logging -128]
+[LoggingExternalInterface logging 42]
+[fuzz-exec] calling rtts
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 1]
+[fuzz-exec] calling br_on_cast
+[LoggingExternalInterface logging 3]
+[trap unreachable]
diff --git a/binaryen/test/passes/Oz_fuzz-exec_all-features.wast b/binaryen/test/passes/Oz_fuzz-exec_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/Oz_fuzz-exec_all-features.wast
@@ -0,0 +1,182 @@
+(module
+ (type $struct (struct i32))
+ (type $extendedstruct (struct i32 f64))
+ (type $bytes (array (mut i8)))
+ (import "fuzzing-support" "log-i32" (func $log (param i32)))
+ (func "structs"
+  (local $x (ref null $struct))
+  (local $y (ref null $struct))
+  (local.set $x
+   (struct.new_default_with_rtt $struct
+    (rtt.canon $struct)
+   )
+  )
+  ;; The value is initialized to 0
+  ;; Note: -Oz will optimize all these to constants thanks to Precompute
+  (call $log
+   (struct.get $struct 0 (local.get $x))
+  )
+  ;; Assigning a value works
+  (struct.set $struct 0
+   (local.get $x)
+   (i32.const 42)
+  )
+  (call $log
+   (struct.get $struct 0 (local.get $x))
+  )
+  ;; References are references, so writing to one's value affects the other's
+  (local.set $y (local.get $x))
+  (struct.set $struct 0
+   (local.get $y)
+   (i32.const 100)
+  )
+  (call $log
+   (struct.get $struct 0 (local.get $x))
+  )
+  (call $log
+   (struct.get $struct 0 (local.get $y))
+  )
+ )
+ (func "arrays"
+  (local $x (ref null $bytes))
+  (local.set $x
+   (array.new_with_rtt $bytes
+    (rtt.canon $bytes)
+    (i32.const 50) ;; size
+    (i32.const 42) ;; value to splat into the array
+   )
+  )
+  ;; The length should be 50
+  (call $log
+   (array.len $bytes (local.get $x))
+  )
+  ;; The value should be 42
+  (call $log
+   (array.get_u $bytes (local.get $x) (i32.const 10))
+  )
+  ;; Write a value that will be truncated into an i8
+  (array.set $bytes (local.get $x) (i32.const 10) (i32.const 0xff80))
+  ;; The value should be 0x80 (-128 or 128 depending on signed/unsigned)
+  (call $log
+   (array.get_u $bytes (local.get $x) (i32.const 10))
+  )
+  (call $log
+   (array.get_s $bytes (local.get $x) (i32.const 10))
+  )
+  ;; Other items than the one at index 10 are unaffected.
+  (call $log
+   (array.get_s $bytes (local.get $x) (i32.const 20))
+  )
+ )
+ (func "rtts"
+  (local $x (rtt $struct))
+  (local $y (rtt $extendedstruct))
+  (local $z (rtt $extendedstruct))
+  (local $any anyref)
+  (local.set $x (rtt.canon $struct))
+  (local.set $y (rtt.sub $extendedstruct (local.get $x)))
+  (local.set $z (rtt.canon $extendedstruct))
+  ;; Casting null returns null.
+  (call $log (ref.is_null
+   (ref.cast $struct (ref.null $struct) (local.get $x))
+  ))
+  ;; Testing null returns 0.
+  (call $log
+   (ref.test $struct (ref.null $struct) (local.get $x))
+  )
+  ;; Testing something completely wrong (struct vs array) returns 0.
+  (call $log
+   (ref.test $struct
+    (array.new_with_rtt $bytes
+     (rtt.canon $bytes)
+     (i32.const 10)
+     (i32.const 20)
+    )
+    (local.get $x)
+   )
+  )
+  ;; Testing a thing with the same RTT returns 1.
+  (call $log
+   (ref.test $struct
+    (struct.new_default_with_rtt $struct
+     (local.get $x)
+    )
+    (local.get $x)
+   )
+  )
+  ;; A bad downcast returns 0: we create a struct, which is not a extendedstruct.
+  (call $log
+   (ref.test $extendedstruct
+    (struct.new_default_with_rtt $struct
+     (local.get $x)
+    )
+    (local.get $z)
+   )
+  )
+  ;; Create a extendedstruct with RTT y, and upcast statically to anyref.
+  (local.set $any
+   (struct.new_default_with_rtt $extendedstruct
+    (local.get $y)
+   )
+  )
+  ;; Casting to y, the exact same RTT, works.
+  (call $log
+   (ref.test $extendedstruct
+    (local.get $any)
+    (local.get $y)
+   )
+  )
+  ;; Casting to z, another RTT of the same data type, fails.
+  (call $log
+   (ref.test $extendedstruct
+    (local.get $any)
+    (local.get $z)
+   )
+  )
+  ;; Casting to x, the parent of y, works.
+  (call $log
+   (ref.test $struct
+    (local.get $any)
+    (local.get $x)
+   )
+  )
+ )
+ (func "br_on_cast"
+  (local $any anyref)
+  ;; create a simple $struct, store it in an anyref
+  (local.set $any
+   (struct.new_default_with_rtt $struct (rtt.canon $struct))
+  )
+  (drop
+   (block $block (result ($ref $struct))
+    (drop
+     (block $extendedblock (result (ref $extendedstruct))
+      (drop
+       ;; second, try to cast our simple $struct to what it is, which will work
+       (br_on_cast $block $struct
+        ;; first, try to cast our simple $struct to an extended, which will fail
+        (br_on_cast $extendedblock $extendedstruct
+         (local.get $any) (rtt.canon $extendedstruct)
+        )
+        (rtt.canon $struct)
+       )
+      )
+      (call $log (i32.const -1)) ;; we should never get here
+      (return)
+     )
+    )
+    (call $log (i32.const -2)) ;; we should never get here either
+    (return)
+   )
+  )
+  (call $log (i32.const 3)) ;; we should get here
+  (drop
+   (block $never (result (ref $extendedstruct))
+    ;; an untaken br_on_cast, with unreachable rtt - so we cannot use the
+    ;; RTT in binaryen IR to find the cast type.
+    (br_on_cast $never $extendedstruct (ref.null $struct) (unreachable))
+    (unreachable)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/asyncify_enable-multivalue.txt b/binaryen/test/passes/asyncify_enable-multivalue.txt
--- a/binaryen/test/passes/asyncify_enable-multivalue.txt
+++ b/binaryen/test/passes/asyncify_enable-multivalue.txt
@@ -491,55 +491,57 @@
        )
       )
       (block
-       (if
-        (if (result i32)
-         (i32.eq
-          (global.get $__asyncify_state)
-          (i32.const 0)
-         )
-         (i32.const 1)
-         (i32.eq
-          (local.get $6)
-          (i32.const 0)
-         )
-        )
-        (block
-         (local.set $7
-          (call $import2)
-         )
-         (if
+       (block
+        (if
+         (if (result i32)
           (i32.eq
            (global.get $__asyncify_state)
-           (i32.const 1)
+           (i32.const 0)
           )
-          (br $__asyncify_unwind
+          (i32.const 1)
+          (i32.eq
+           (local.get $6)
            (i32.const 0)
           )
-          (local.set $1
-           (local.get $7)
+         )
+         (block
+          (local.set $7
+           (call $import2)
           )
+          (if
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 1)
+           )
+           (br $__asyncify_unwind
+            (i32.const 0)
+           )
+           (local.set $1
+            (local.get $7)
+           )
+          )
          )
         )
-       )
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
-        )
-        (block
-         (local.set $temp
-          (local.get $1)
-         )
-         (local.set $2
-          (local.get $temp)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
          )
-         (return
-          (local.get $2)
+         (block
+          (local.set $temp
+           (local.get $1)
+          )
+          (local.set $2
+           (local.get $temp)
+          )
+          (return
+           (local.get $2)
+          )
          )
         )
+        (nop)
+        (nop)
        )
-       (nop)
-       (nop)
       )
       (unreachable)
      )
@@ -814,84 +816,86 @@
        )
       )
       (block
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
-        )
-        (loop $l
-         (local.set $3
-          (local.get $y)
-         )
-         (local.set $4
-          (i32.add
-           (local.get $3)
-           (i32.const 1)
-          )
-         )
-         (local.set $x
-          (local.get $4)
-         )
-         (local.set $5
-          (local.get $x)
-         )
-         (local.set $6
-          (i32.div_s
-           (local.get $5)
-           (i32.const 3)
-          )
-         )
-         (local.set $y
-          (local.get $6)
-         )
-         (local.set $7
-          (local.get $y)
-         )
-         (br_if $l
-          (local.get $7)
-         )
-        )
-       )
-       (if
-        (if (result i32)
+       (block
+        (if
          (i32.eq
           (global.get $__asyncify_state)
           (i32.const 0)
          )
-         (i32.const 1)
-         (i32.eq
-          (local.get $12)
-          (i32.const 0)
+         (loop $l
+          (local.set $3
+           (local.get $y)
+          )
+          (local.set $4
+           (i32.add
+            (local.get $3)
+            (i32.const 1)
+           )
+          )
+          (local.set $x
+           (local.get $4)
+          )
+          (local.set $5
+           (local.get $x)
+          )
+          (local.set $6
+           (i32.div_s
+            (local.get $5)
+            (i32.const 3)
+           )
+          )
+          (local.set $y
+           (local.get $6)
+          )
+          (local.set $7
+           (local.get $y)
+          )
+          (br_if $l
+           (local.get $7)
+          )
          )
         )
-        (block
-         (call $import)
-         (if
+        (if
+         (if (result i32)
           (i32.eq
            (global.get $__asyncify_state)
-           (i32.const 1)
+           (i32.const 0)
           )
-          (br $__asyncify_unwind
+          (i32.const 1)
+          (i32.eq
+           (local.get $12)
            (i32.const 0)
           )
          )
-        )
-       )
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
+         (block
+          (call $import)
+          (if
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 1)
+           )
+           (br $__asyncify_unwind
+            (i32.const 0)
+           )
+          )
+         )
         )
-        (block
-         (local.set $8
-          (local.get $y)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
          )
-         (return
-          (local.get $8)
+         (block
+          (local.set $8
+           (local.get $y)
+          )
+          (return
+           (local.get $8)
+          )
          )
         )
+        (nop)
        )
-       (nop)
       )
       (unreachable)
      )
@@ -1291,90 +1295,92 @@
       )
       (block
        (block
-        (if
-         (i32.eq
-          (global.get $__asyncify_state)
-          (i32.const 0)
-         )
-         (local.set $1
-          (local.get $x)
-         )
-        )
         (block
          (if
           (i32.eq
            (global.get $__asyncify_state)
            (i32.const 0)
           )
-          (local.set $4
-           (local.get $1)
+          (local.set $1
+           (local.get $x)
           )
          )
-         (if
-          (i32.or
-           (local.get $4)
-           (i32.eq
-            (global.get $__asyncify_state)
-            (i32.const 2)
-           )
-          )
+         (block
           (if
            (i32.eq
             (global.get $__asyncify_state)
             (i32.const 0)
            )
-           (return
-            (i32.const 1)
-           )
-          )
-         )
-         (if
-          (i32.or
-           (i32.eqz
-            (local.get $4)
-           )
-           (i32.eq
-            (global.get $__asyncify_state)
-            (i32.const 2)
+           (local.set $4
+            (local.get $1)
            )
           )
           (if
-           (if (result i32)
+           (i32.or
+            (local.get $4)
             (i32.eq
              (global.get $__asyncify_state)
-             (i32.const 0)
+             (i32.const 2)
             )
-            (i32.const 1)
+           )
+           (if
             (i32.eq
-             (local.get $6)
+             (global.get $__asyncify_state)
              (i32.const 0)
             )
+            (return
+             (i32.const 1)
+            )
            )
-           (block
-            (call $import3
+          )
+          (if
+           (i32.or
+            (i32.eqz
+             (local.get $4)
+            )
+            (i32.eq
+             (global.get $__asyncify_state)
              (i32.const 2)
             )
-            (if
+           )
+           (if
+            (if (result i32)
              (i32.eq
               (global.get $__asyncify_state)
-              (i32.const 1)
+              (i32.const 0)
              )
-             (br $__asyncify_unwind
+             (i32.const 1)
+             (i32.eq
+              (local.get $6)
               (i32.const 0)
              )
             )
+            (block
+             (call $import3
+              (i32.const 2)
+             )
+             (if
+              (i32.eq
+               (global.get $__asyncify_state)
+               (i32.const 1)
+              )
+              (br $__asyncify_unwind
+               (i32.const 0)
+              )
+             )
+            )
            )
           )
          )
         )
-       )
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
-        )
-        (return
-         (i32.const 3)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (return
+          (i32.const 3)
+         )
         )
        )
       )
@@ -1470,90 +1476,92 @@
       )
       (block
        (block
-        (if
-         (i32.eq
-          (global.get $__asyncify_state)
-          (i32.const 0)
-         )
-         (local.set $1
-          (local.get $x)
-         )
-        )
         (block
          (if
           (i32.eq
            (global.get $__asyncify_state)
            (i32.const 0)
           )
-          (local.set $4
-           (local.get $1)
+          (local.set $1
+           (local.get $x)
           )
          )
-         (if
-          (i32.or
-           (local.get $4)
+         (block
+          (if
            (i32.eq
             (global.get $__asyncify_state)
-            (i32.const 2)
+            (i32.const 0)
            )
+           (local.set $4
+            (local.get $1)
+           )
           )
           (if
-           (if (result i32)
+           (i32.or
+            (local.get $4)
             (i32.eq
              (global.get $__asyncify_state)
-             (i32.const 0)
-            )
-            (i32.const 1)
-            (i32.eq
-             (local.get $6)
-             (i32.const 0)
+             (i32.const 2)
             )
            )
-           (block
-            (call $import3
-             (i32.const 1)
-            )
-            (if
+           (if
+            (if (result i32)
              (i32.eq
               (global.get $__asyncify_state)
-              (i32.const 1)
+              (i32.const 0)
              )
-             (br $__asyncify_unwind
+             (i32.const 1)
+             (i32.eq
+              (local.get $6)
               (i32.const 0)
              )
             )
-           )
-          )
-         )
-         (if
-          (i32.or
-           (i32.eqz
-            (local.get $4)
-           )
-           (i32.eq
-            (global.get $__asyncify_state)
-            (i32.const 2)
+            (block
+             (call $import3
+              (i32.const 1)
+             )
+             (if
+              (i32.eq
+               (global.get $__asyncify_state)
+               (i32.const 1)
+              )
+              (br $__asyncify_unwind
+               (i32.const 0)
+              )
+             )
+            )
            )
           )
           (if
-           (i32.eq
-            (global.get $__asyncify_state)
-            (i32.const 0)
+           (i32.or
+            (i32.eqz
+             (local.get $4)
+            )
+            (i32.eq
+             (global.get $__asyncify_state)
+             (i32.const 2)
+            )
            )
-           (return
-            (i32.const 2)
+           (if
+            (i32.eq
+             (global.get $__asyncify_state)
+             (i32.const 0)
+            )
+            (return
+             (i32.const 2)
+            )
            )
           )
          )
         )
-       )
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
-        )
-        (return
-         (i32.const 3)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
+         )
+         (return
+          (i32.const 3)
+         )
         )
        )
       )
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt b/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt
--- a/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt
+++ b/binaryen/test/passes/asyncify_mod-asyncify-always-and-only-unwind.txt
@@ -152,52 +152,54 @@
        )
       )
       (block
-       (if
-        (if (result i32)
-         (i32.eq
-          (global.get $__asyncify_state)
-          (i32.const 0)
-         )
-         (i32.const 1)
-         (i32.eq
-          (local.get $6)
-          (i32.const 0)
-         )
-        )
-        (block
-         (local.set $7
-          (call $import2)
-         )
-         (if
+       (block
+        (if
+         (if (result i32)
+          (i32.eq
+           (global.get $__asyncify_state)
+           (i32.const 0)
+          )
           (i32.const 1)
-          (br $__asyncify_unwind
+          (i32.eq
+           (local.get $6)
            (i32.const 0)
           )
-          (local.set $1
-           (local.get $7)
+         )
+         (block
+          (local.set $7
+           (call $import2)
           )
+          (if
+           (i32.const 1)
+           (br $__asyncify_unwind
+            (i32.const 0)
+           )
+           (local.set $1
+            (local.get $7)
+           )
+          )
          )
         )
-       )
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
-        )
-        (block
-         (local.set $temp
-          (local.get $1)
-         )
-         (local.set $2
-          (local.get $temp)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
          )
-         (return
-          (local.get $2)
+         (block
+          (local.set $temp
+           (local.get $1)
+          )
+          (local.set $2
+           (local.get $temp)
+          )
+          (return
+           (local.get $2)
+          )
          )
         )
+        (nop)
+        (nop)
        )
-       (nop)
-       (nop)
       )
       (unreachable)
      )
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.txt b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.txt
--- a/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.txt
+++ b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind.txt
@@ -164,52 +164,54 @@
        )
       )
       (block
-       (if
-        (if (result i32)
-         (i32.eq
-          (global.get $__asyncify_state)
-          (i32.const 0)
-         )
-         (i32.const 1)
-         (i32.eq
-          (local.get $6)
-          (i32.const 0)
-         )
-        )
-        (block
-         (local.set $7
-          (call $import2)
-         )
-         (if
-          (i32.const 0)
-          (br $__asyncify_unwind
+       (block
+        (if
+         (if (result i32)
+          (i32.eq
+           (global.get $__asyncify_state)
            (i32.const 0)
           )
-          (local.set $1
-           (local.get $7)
+          (i32.const 1)
+          (i32.eq
+           (local.get $6)
+           (i32.const 0)
           )
          )
-        )
-       )
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
-        )
-        (block
-         (local.set $temp
-          (local.get $1)
+         (block
+          (local.set $7
+           (call $import2)
+          )
+          (if
+           (i32.const 0)
+           (br $__asyncify_unwind
+            (i32.const 0)
+           )
+           (local.set $1
+            (local.get $7)
+           )
+          )
          )
-         (local.set $2
-          (local.get $temp)
+        )
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
          )
-         (return
-          (local.get $2)
+         (block
+          (local.set $temp
+           (local.get $1)
+          )
+          (local.set $2
+           (local.get $temp)
+          )
+          (return
+           (local.get $2)
+          )
          )
         )
+        (nop)
+        (nop)
        )
-       (nop)
-       (nop)
       )
       (unreachable)
      )
diff --git a/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.txt b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.txt
--- a/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.txt
+++ b/binaryen/test/passes/asyncify_mod-asyncify-never-unwind_O.txt
@@ -27,11 +27,11 @@
       (block (result i32)
        (i32.store
         (global.get $__asyncify_data)
-        (i32.add
+        (i32.sub
          (i32.load
           (global.get $__asyncify_data)
          )
-         (i32.const -4)
+         (i32.const 4)
         )
        )
        (i32.load
diff --git a/binaryen/test/passes/asyncify_optimize-level=1.txt b/binaryen/test/passes/asyncify_optimize-level=1.txt
--- a/binaryen/test/passes/asyncify_optimize-level=1.txt
+++ b/binaryen/test/passes/asyncify_optimize-level=1.txt
@@ -29,11 +29,11 @@
         (block (result i32)
          (i32.store
           (global.get $__asyncify_data)
-          (i32.add
+          (i32.sub
            (i32.load
             (global.get $__asyncify_data)
            )
-           (i32.const -4)
+           (i32.const 4)
           )
          )
          (i32.load
@@ -91,11 +91,11 @@
    (block
     (i32.store
      (global.get $__asyncify_data)
-     (i32.add
+     (i32.sub
       (i32.load
        (global.get $__asyncify_data)
       )
-      (i32.const -4)
+      (i32.const 4)
      )
     )
     (local.set $0
@@ -120,11 +120,11 @@
         (block (result i32)
          (i32.store
           (global.get $__asyncify_data)
-          (i32.add
+          (i32.sub
            (i32.load
             (global.get $__asyncify_data)
            )
-           (i32.const -4)
+           (i32.const 4)
           )
          )
          (i32.load
@@ -215,11 +215,11 @@
         (block (result i32)
          (i32.store
           (global.get $__asyncify_data)
-          (i32.add
+          (i32.sub
            (i32.load
             (global.get $__asyncify_data)
            )
-           (i32.const -4)
+           (i32.const 4)
           )
          )
          (i32.load
@@ -282,11 +282,11 @@
    (block
     (i32.store
      (global.get $__asyncify_data)
-     (i32.add
+     (i32.sub
       (i32.load
        (global.get $__asyncify_data)
       )
-      (i32.const -4)
+      (i32.const 4)
      )
     )
     (local.set $1
@@ -308,11 +308,11 @@
      (block
       (i32.store
        (global.get $__asyncify_data)
-       (i32.add
+       (i32.sub
         (i32.load
          (global.get $__asyncify_data)
         )
-        (i32.const -4)
+        (i32.const 4)
        )
       )
       (local.set $2
@@ -418,11 +418,11 @@
      (block
       (i32.store
        (global.get $__asyncify_data)
-       (i32.add
+       (i32.sub
         (i32.load
          (global.get $__asyncify_data)
         )
-        (i32.const -4)
+        (i32.const 4)
        )
       )
       (local.set $1
@@ -494,11 +494,11 @@
    (block
     (i32.store
      (global.get $__asyncify_data)
-     (i32.add
+     (i32.sub
       (i32.load
        (global.get $__asyncify_data)
       )
-      (i32.const -4)
+      (i32.const 4)
      )
     )
     (local.set $1
@@ -520,11 +520,11 @@
      (block
       (i32.store
        (global.get $__asyncify_data)
-       (i32.add
+       (i32.sub
         (i32.load
          (global.get $__asyncify_data)
         )
-        (i32.const -4)
+        (i32.const 4)
        )
       )
       (local.set $2
@@ -656,11 +656,11 @@
      (block
       (i32.store
        (global.get $__asyncify_data)
-       (i32.add
+       (i32.sub
         (i32.load
          (global.get $__asyncify_data)
         )
-        (i32.const -4)
+        (i32.const 4)
        )
       )
       (local.set $1
@@ -768,11 +768,11 @@
    (block
     (i32.store
      (global.get $__asyncify_data)
-     (i32.add
+     (i32.sub
       (i32.load
        (global.get $__asyncify_data)
       )
-      (i32.const -4)
+      (i32.const 4)
      )
     )
     (local.set $1
@@ -794,11 +794,11 @@
      (block
       (i32.store
        (global.get $__asyncify_data)
-       (i32.add
+       (i32.sub
         (i32.load
          (global.get $__asyncify_data)
         )
-        (i32.const -4)
+        (i32.const 4)
        )
       )
       (local.set $2
@@ -920,11 +920,11 @@
    (block
     (i32.store
      (global.get $__asyncify_data)
-     (i32.add
+     (i32.sub
       (i32.load
        (global.get $__asyncify_data)
       )
-      (i32.const -4)
+      (i32.const 4)
      )
     )
     (local.set $0
@@ -946,11 +946,11 @@
      (block
       (i32.store
        (global.get $__asyncify_data)
-       (i32.add
+       (i32.sub
         (i32.load
          (global.get $__asyncify_data)
         )
-        (i32.const -4)
+        (i32.const 4)
        )
       )
       (local.set $1
@@ -1046,11 +1046,11 @@
    (block
     (i32.store
      (global.get $__asyncify_data)
-     (i32.add
+     (i32.sub
       (i32.load
        (global.get $__asyncify_data)
       )
-      (i32.const -4)
+      (i32.const 4)
      )
     )
     (local.set $0
@@ -1072,11 +1072,11 @@
      (block
       (i32.store
        (global.get $__asyncify_data)
-       (i32.add
+       (i32.sub
         (i32.load
          (global.get $__asyncify_data)
         )
-        (i32.const -4)
+        (i32.const 4)
        )
       )
       (local.set $2
@@ -1171,11 +1171,11 @@
      (block
       (i32.store
        (global.get $__asyncify_data)
-       (i32.add
+       (i32.sub
         (i32.load
          (global.get $__asyncify_data)
         )
-        (i32.const -4)
+        (i32.const 4)
        )
       )
       (local.set $0
@@ -1276,11 +1276,11 @@
      (block
       (i32.store
        (global.get $__asyncify_data)
-       (i32.add
+       (i32.sub
         (i32.load
          (global.get $__asyncify_data)
         )
-        (i32.const -4)
+        (i32.const 4)
        )
       )
       (local.set $0
@@ -1384,11 +1384,11 @@
         (block (result i32)
          (i32.store
           (global.get $__asyncify_data)
-          (i32.add
+          (i32.sub
            (i32.load
             (global.get $__asyncify_data)
            )
-           (i32.const -4)
+           (i32.const 4)
           )
          )
          (i32.load
diff --git a/binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt b/binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt
--- a/binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt
+++ b/binaryen/test/passes/asyncify_pass-arg=asyncify-imports@env.import,env.import2.txt
@@ -488,55 +488,57 @@
        )
       )
       (block
-       (if
-        (if (result i32)
-         (i32.eq
-          (global.get $__asyncify_state)
-          (i32.const 0)
-         )
-         (i32.const 1)
-         (i32.eq
-          (local.get $6)
-          (i32.const 0)
-         )
-        )
-        (block
-         (local.set $7
-          (call $import2)
-         )
-         (if
+       (block
+        (if
+         (if (result i32)
           (i32.eq
            (global.get $__asyncify_state)
-           (i32.const 1)
+           (i32.const 0)
           )
-          (br $__asyncify_unwind
+          (i32.const 1)
+          (i32.eq
+           (local.get $6)
            (i32.const 0)
           )
-          (local.set $1
-           (local.get $7)
+         )
+         (block
+          (local.set $7
+           (call $import2)
           )
+          (if
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 1)
+           )
+           (br $__asyncify_unwind
+            (i32.const 0)
+           )
+           (local.set $1
+            (local.get $7)
+           )
+          )
          )
         )
-       )
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
-        )
-        (block
-         (local.set $temp
-          (local.get $1)
-         )
-         (local.set $2
-          (local.get $temp)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
          )
-         (return
-          (local.get $2)
+         (block
+          (local.set $temp
+           (local.get $1)
+          )
+          (local.set $2
+           (local.get $temp)
+          )
+          (return
+           (local.get $2)
+          )
          )
         )
+        (nop)
+        (nop)
        )
-       (nop)
-       (nop)
       )
       (unreachable)
      )
@@ -810,84 +812,86 @@
        )
       )
       (block
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
-        )
-        (loop $l
-         (local.set $2
-          (local.get $y)
-         )
-         (local.set $3
-          (i32.add
-           (local.get $2)
-           (i32.const 1)
-          )
-         )
-         (local.set $x
-          (local.get $3)
-         )
-         (local.set $4
-          (local.get $x)
-         )
-         (local.set $5
-          (i32.div_s
-           (local.get $4)
-           (i32.const 3)
-          )
-         )
-         (local.set $y
-          (local.get $5)
-         )
-         (local.set $6
-          (local.get $y)
-         )
-         (br_if $l
-          (local.get $6)
-         )
-        )
-       )
-       (if
-        (if (result i32)
+       (block
+        (if
          (i32.eq
           (global.get $__asyncify_state)
           (i32.const 0)
          )
-         (i32.const 1)
-         (i32.eq
-          (local.get $11)
-          (i32.const 0)
+         (loop $l
+          (local.set $2
+           (local.get $y)
+          )
+          (local.set $3
+           (i32.add
+            (local.get $2)
+            (i32.const 1)
+           )
+          )
+          (local.set $x
+           (local.get $3)
+          )
+          (local.set $4
+           (local.get $x)
+          )
+          (local.set $5
+           (i32.div_s
+            (local.get $4)
+            (i32.const 3)
+           )
+          )
+          (local.set $y
+           (local.get $5)
+          )
+          (local.set $6
+           (local.get $y)
+          )
+          (br_if $l
+           (local.get $6)
+          )
          )
         )
-        (block
-         (call $import)
-         (if
+        (if
+         (if (result i32)
           (i32.eq
            (global.get $__asyncify_state)
-           (i32.const 1)
+           (i32.const 0)
           )
-          (br $__asyncify_unwind
+          (i32.const 1)
+          (i32.eq
+           (local.get $11)
            (i32.const 0)
           )
          )
-        )
-       )
-       (if
-        (i32.eq
-         (global.get $__asyncify_state)
-         (i32.const 0)
+         (block
+          (call $import)
+          (if
+           (i32.eq
+            (global.get $__asyncify_state)
+            (i32.const 1)
+           )
+           (br $__asyncify_unwind
+            (i32.const 0)
+           )
+          )
+         )
         )
-        (block
-         (local.set $7
-          (local.get $y)
+        (if
+         (i32.eq
+          (global.get $__asyncify_state)
+          (i32.const 0)
          )
-         (return
-          (local.get $7)
+         (block
+          (local.set $7
+           (local.get $y)
+          )
+          (return
+           (local.get $7)
+          )
          )
         )
+        (nop)
        )
-       (nop)
       )
       (unreachable)
      )
@@ -1062,21 +1066,23 @@
   (local $2 i32)
   (local $3 i32)
   (block
-   (local.set $1
-    (local.get $x)
-   )
-   (if
-    (local.get $1)
-    (return
-     (i32.const 1)
+   (block
+    (local.set $1
+     (local.get $x)
     )
-    (call $import3
-     (i32.const 2)
+    (if
+     (local.get $1)
+     (return
+      (i32.const 1)
+     )
+     (call $import3
+      (i32.const 2)
+     )
     )
    )
-  )
-  (return
-   (i32.const 3)
+   (return
+    (i32.const 3)
+   )
   )
  )
  (func $calls-import2-if-else-oneside2 (param $x i32) (result i32)
@@ -1084,21 +1090,23 @@
   (local $2 i32)
   (local $3 i32)
   (block
-   (local.set $1
-    (local.get $x)
-   )
-   (if
-    (local.get $1)
-    (call $import3
-     (i32.const 1)
+   (block
+    (local.set $1
+     (local.get $x)
     )
-    (return
-     (i32.const 2)
+    (if
+     (local.get $1)
+     (call $import3
+      (i32.const 1)
+     )
+     (return
+      (i32.const 2)
+     )
     )
    )
-  )
-  (return
-   (i32.const 3)
+   (return
+    (i32.const 3)
+   )
   )
  )
  (func $calls-loop (param $x i32)
diff --git a/binaryen/test/passes/converge_O3_metrics.bin.txt b/binaryen/test/passes/converge_O3_metrics.bin.txt
--- a/binaryen/test/passes/converge_O3_metrics.bin.txt
+++ b/binaryen/test/passes/converge_O3_metrics.bin.txt
@@ -6,18 +6,18 @@
  [imports]      : 3       
  [memory-data]  : 28      
  [table-data]   : 429     
- [total]        : 132     
+ [total]        : 129     
  [vars]         : 4       
  binary         : 12      
  block          : 8       
  break          : 3       
  call           : 3       
  call_indirect  : 4       
- const          : 47      
+ const          : 45      
  drop           : 3       
  global.get     : 1       
  global.set     : 1       
- if             : 3       
+ if             : 2       
  load           : 16      
  local.get      : 18      
  local.set      : 7       
@@ -30,7 +30,7 @@
  (type $none_=>_i32 (func (result i32)))
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32 i32 i32) (result i32)))
- (import "env" "memory" (memory $mimport$1 256 256))
+ (import "env" "memory" (memory $mimport$0 256 256))
  (data (i32.const 2948) "\03")
  (data (i32.const 6828) "\04")
  (data (i32.const 7028) "\0d\00\00\00\06")
@@ -39,7 +39,7 @@
  (data (i32.const 18128) ",I")
  (data (i32.const 18732) "D\1b")
  (data (i32.const 18764) "`\0b")
- (import "env" "table" (table $timport$2 478 478 funcref))
+ (import "env" "table" (table $timport$0 478 478 funcref))
  (elem (i32.const 0) $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $___stdout_write $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $__ZNSt3__211__stdoutbufIcE6xsputnEPKci $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $__ZNSt3__211__stdoutbufIcE8overflowEi)
  (import "env" "___syscall146" (func $import$0 (param i32 i32) (result i32)))
  (global $global$0 (mut i32) (i32.const 1))
@@ -71,13 +71,9 @@
    (i32.const 2)
   )
   (drop
-   (if (result i32)
-    (call $import$0
-     (i32.const 146)
-     (local.get $0)
-    )
-    (i32.const -1)
-    (i32.const 0)
+   (call $import$0
+    (i32.const 146)
+    (local.get $0)
    )
   )
   (i32.const 1)
@@ -89,11 +85,11 @@
    (i32.load offset=24
     (i32.add
      (i32.load
-      (i32.add
+      (i32.sub
        (i32.load
         (i32.const 18100)
        )
-       (i32.const -12)
+       (i32.const 12)
       )
      )
      (i32.const 18100)
@@ -167,11 +163,11 @@
          (i32.load
           (i32.add
            (i32.load
-            (i32.add
+            (i32.sub
              (i32.load
               (i32.const 18100)
              )
-             (i32.const -12)
+             (i32.const 12)
             )
            )
            (i32.const 18124)
@@ -251,18 +247,18 @@
  [imports]      : 3       
  [memory-data]  : 28      
  [table-data]   : 429     
- [total]        : 132     
+ [total]        : 129     
  [vars]         : 4       
  binary         : 12      
  block          : 8       
  break          : 3       
  call           : 3       
  call_indirect  : 4       
- const          : 47      
+ const          : 45      
  drop           : 3       
  global.get     : 1       
  global.set     : 1       
- if             : 3       
+ if             : 2       
  load           : 16      
  local.get      : 18      
  local.set      : 7       
@@ -275,7 +271,7 @@
  (type $none_=>_i32 (func (result i32)))
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32 i32 i32) (result i32)))
- (import "env" "memory" (memory $mimport$1 256 256))
+ (import "env" "memory" (memory $mimport$0 256 256))
  (data (i32.const 2948) "\03")
  (data (i32.const 6828) "\04")
  (data (i32.const 7028) "\0d\00\00\00\06")
@@ -284,7 +280,7 @@
  (data (i32.const 18128) ",I")
  (data (i32.const 18732) "D\1b")
  (data (i32.const 18764) "`\0b")
- (import "env" "table" (table $timport$2 478 478 funcref))
+ (import "env" "table" (table $timport$0 478 478 funcref))
  (elem (i32.const 0) $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $___stdout_write $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $__ZNSt3__211__stdoutbufIcE6xsputnEPKci $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $b0 $__ZNSt3__211__stdoutbufIcE8overflowEi)
  (import "env" "___syscall146" (func $import$0 (param i32 i32) (result i32)))
  (global $global$0 (mut i32) (i32.const 1))
@@ -316,13 +312,9 @@
    (i32.const 2)
   )
   (drop
-   (if (result i32)
-    (call $import$0
-     (i32.const 146)
-     (local.get $0)
-    )
-    (i32.const -1)
-    (i32.const 0)
+   (call $import$0
+    (i32.const 146)
+    (local.get $0)
    )
   )
   (i32.const 1)
@@ -334,11 +326,11 @@
    (i32.load offset=24
     (i32.add
      (i32.load
-      (i32.add
+      (i32.sub
        (i32.load
         (i32.const 18100)
        )
-       (i32.const -12)
+       (i32.const 12)
       )
      )
      (i32.const 18100)
@@ -412,11 +404,11 @@
          (i32.load
           (i32.add
            (i32.load
-            (i32.add
+            (i32.sub
              (i32.load
               (i32.const 18100)
              )
-             (i32.const -12)
+             (i32.const 12)
             )
            )
            (i32.const 18124)
diff --git a/binaryen/test/passes/dae_all-features.txt b/binaryen/test/passes/dae_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dae_all-features.txt
@@ -0,0 +1,293 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $f64_=>_none (func (param f64)))
+ (table $0 2 2 funcref)
+ (elem (i32.const 0) $a9 $c8)
+ (export "a8" (func $a8))
+ (func $a
+  (local $0 i32)
+  (local.set $0
+   (i32.const 1)
+  )
+  (nop)
+ )
+ (func $b
+  (call $a)
+ )
+ (func $a1
+  (local $0 i32)
+  (local.set $0
+   (i32.const 2)
+  )
+  (unreachable)
+ )
+ (func $b1
+  (call $a1)
+ )
+ (func $b11
+  (call $a1)
+ )
+ (func $a2 (param $x i32)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $b2
+  (call $a2
+   (i32.const 3)
+  )
+ )
+ (func $b22
+  (call $a2
+   (i32.const 4)
+  )
+ )
+ (func $a3
+  (local $0 i32)
+  (drop
+   (i32.const -1)
+  )
+ )
+ (func $b3
+  (call $a3)
+ )
+ (func $b33
+  (call $a3)
+ )
+ (func $a4 (param $x i32)
+  (nop)
+ )
+ (func $b4
+  (call $a4
+   (unreachable)
+  )
+ )
+ (func $b43
+  (call $a4
+   (i32.const 4)
+  )
+ )
+ (func $a5
+  (local $0 f64)
+  (local $1 i32)
+  (local.set $0
+   (f64.const 3.14159)
+  )
+  (block
+   (local.set $1
+    (i32.const 1)
+   )
+   (block
+    (drop
+     (local.get $1)
+    )
+    (drop
+     (local.get $0)
+    )
+   )
+  )
+ )
+ (func $b5
+  (call $a5)
+ )
+ (func $a6 (param $0 i32)
+  (local $1 f64)
+  (local.set $1
+   (f64.const 3.14159)
+  )
+  (block
+   (drop
+    (local.get $0)
+   )
+   (drop
+    (local.get $1)
+   )
+  )
+ )
+ (func $b6
+  (call $a6
+   (unreachable)
+  )
+ )
+ (func $a7 (param $0 f64)
+  (local $1 i32)
+  (local.set $1
+   (i32.const 1)
+  )
+  (block
+   (drop
+    (local.get $1)
+   )
+   (drop
+    (local.get $0)
+   )
+  )
+ )
+ (func $b7
+  (call $a7
+   (unreachable)
+  )
+ )
+ (func $a8 (param $x i32)
+  (nop)
+ )
+ (func $b8
+  (call $a8
+   (i32.const 1)
+  )
+ )
+ (func $a9 (param $x i32)
+  (nop)
+ )
+ (func $b9
+  (call $a9
+   (i32.const 1)
+  )
+ )
+ (func $a10
+  (local $0 i32)
+  (local.set $0
+   (i32.const 1)
+  )
+  (block
+   (call $a10)
+   (call $a10)
+  )
+ )
+ (func $a11
+  (local $0 i32)
+  (call $a11)
+  (call $a11)
+ )
+ (func $a12 (param $x i32)
+  (drop
+   (local.get $x)
+  )
+  (call $a12
+   (i32.const 1)
+  )
+  (call $a12
+   (i32.const 2)
+  )
+ )
+ (func $c1
+  (local $x i32)
+  (call $c2)
+  (call $c3)
+  (call $c3)
+  (drop
+   (call $c4)
+  )
+  (local.set $x
+   (call $c4)
+  )
+  (call $c5
+   (unreachable)
+  )
+  (call $c6)
+  (call $c7)
+  (drop
+   (call $c8)
+  )
+ )
+ (func $c2
+  (drop
+   (i32.const 1)
+  )
+ )
+ (func $c3
+  (drop
+   (i32.const 2)
+  )
+ )
+ (func $c4 (result i32)
+  (i32.const 3)
+ )
+ (func $c5 (param $x i32)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $c6
+  (unreachable)
+ )
+ (func $c7
+  (drop
+   (i32.const 4)
+  )
+  (return)
+ )
+ (func $c8 (result i32)
+  (i32.const 5)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (export "a" (func $0))
+ (func $0
+  (call $b)
+ )
+ (func $b
+  (local $0 i32)
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i32.const 1)
+    )
+    (local.get $0)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (func $foo (param $x i32) (result i32)
+  (drop
+   (return_call $bar)
+  )
+  (i32.const 42)
+ )
+ (func $bar (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.const 0)
+  )
+  (i32.const 7)
+ )
+)
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_none (func))
+ (table $0 1 1 funcref)
+ (func $foo (result i32)
+  (local $0 i32)
+  (local.set $0
+   (i32.const 42)
+  )
+  (drop
+   (return_call_indirect (type $none_=>_i32)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $bar
+  (drop
+   (call $foo)
+  )
+ )
+)
+(module
+ (type $funcref_i32_f64_=>_i64 (func (param funcref i32 f64) (result i64)))
+ (type $f32_=>_funcref (func (param f32) (result funcref)))
+ (export "export" (func $1))
+ (func $0 (param $0 funcref) (param $1 i32) (param $2 f64) (result i64)
+  (nop)
+  (unreachable)
+ )
+ (func $1 (param $0 f32) (result funcref)
+  (ref.func $0)
+ )
+)
diff --git a/binaryen/test/passes/dae_all-features.wast b/binaryen/test/passes/dae_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dae_all-features.wast
@@ -0,0 +1,174 @@
+(module
+  (export "a8" (func $a8))
+  (table 2 2 funcref)
+  (elem (i32.const 0) $a9 $c8)
+  (func $a (param $x i32))
+  (func $b
+    (call $a (i32.const 1)) ;; best case scenario
+  )
+  (func $a1 (param $x i32)
+    (unreachable)
+  )
+  (func $b1
+    (call $a1 (i32.const 2)) ;; same value in both, so works
+  )
+  (func $b11
+    (call $a1 (i32.const 2))
+  )
+  (func $a2 (param $x i32)
+    (drop (local.get $x))
+  )
+  (func $b2
+    (call $a2 (i32.const 3)) ;; different value!
+  )
+  (func $b22
+    (call $a2 (i32.const 4))
+  )
+  (func $a3 (param $x i32)
+    (drop (i32.const -1)) ;; diff value, but at least unused, so no need to send
+  )
+  (func $b3
+    (call $a3 (i32.const 3))
+  )
+  (func $b33
+    (call $a3 (i32.const 4))
+  )
+  (func $a4 (param $x i32) ;; diff value, but with effects
+  )
+  (func $b4
+    (call $a4 (unreachable))
+  )
+  (func $b43
+    (call $a4 (i32.const 4))
+  )
+  (func $a5 (param $x i32) (param $y f64) ;; optimize two
+    (drop (local.get $x))
+    (drop (local.get $y))
+  )
+  (func $b5
+    (call $a5 (i32.const 1) (f64.const 3.14159))
+  )
+  (func $a6 (param $x i32) (param $y f64) ;; optimize just one
+    (drop (local.get $x))
+    (drop (local.get $y))
+  )
+  (func $b6
+    (call $a6 (unreachable) (f64.const 3.14159))
+  )
+  (func $a7 (param $x i32) (param $y f64) ;; optimize just the other one
+    (drop (local.get $x))
+    (drop (local.get $y))
+  )
+  (func $b7
+    (call $a7 (i32.const 1) (unreachable))
+  )
+  (func $a8 (param $x i32)) ;; exported, do not optimize
+  (func $b8
+    (call $a8 (i32.const 1))
+  )
+  (func $a9 (param $x i32)) ;; tabled, do not optimize
+  (func $b9
+    (call $a9 (i32.const 1))
+  )
+  (func $a10 (param $x i32) ;; recursion
+    (call $a10 (i32.const 1))
+    (call $a10 (i32.const 1))
+  )
+  (func $a11 (param $x i32) ;; partially successful recursion
+    (call $a11 (i32.const 1))
+    (call $a11 (i32.const 2))
+  )
+  (func $a12 (param $x i32) ;; unsuccessful recursion
+    (drop (local.get $x))
+    (call $a12 (i32.const 1))
+    (call $a12 (i32.const 2))
+  )
+  ;; return values
+  (func $c1
+    (local $x i32)
+    (drop (call $c2))
+    (drop (call $c3))
+    (drop (call $c3))
+    (drop (call $c4))
+    (local.set $x (call $c4))
+    (drop (call $c5 (unreachable)))
+    (drop (call $c6))
+    (drop (call $c7))
+    (drop (call $c8))
+  )
+  (func $c2 (result i32)
+    (i32.const 1)
+  )
+  (func $c3 (result i32)
+    (i32.const 2)
+  )
+  (func $c4 (result i32)
+    (i32.const 3)
+  )
+  (func $c5 (param $x i32) (result i32)
+    (local.get $x)
+  )
+  (func $c6 (result i32)
+    (unreachable)
+  )
+  (func $c7 (result i32)
+    (return (i32.const 4))
+  )
+  (func $c8 (result i32)
+    (i32.const 5)
+  )
+)
+(module ;; both operations at once: remove params and return value
+  (func "a"
+    (drop
+      (call $b
+        (i32.const 1)
+      )
+    )
+  )
+  (func $b (param $x i32) (result i32)
+    (local.get $x)
+  )
+)
+(module ;; tail calls inhibit dropped result removal
+  (func $foo (param $x i32) (result i32)
+    (drop
+      (return_call $bar
+        (i32.const 0)
+      )
+    )
+    (i32.const 42)
+  )
+  (func $bar (param $x i32) (result i32)
+    (i32.const 7)
+  )
+)
+(module ;; indirect tail calls inhibit dropped result removal
+  (type $T (func (result i32)))
+  (table 1 1 funcref)
+  (func $foo (param $x i32) (result i32)
+    (drop
+      (return_call_indirect (type $T)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $bar
+    (drop
+      (call $foo
+        (i32.const 42)
+      )
+    )
+  )
+)
+(module
+ (func $0 (param $0 funcref) (param $1 i32) (param $2 f64) (result i64)
+  (nop)
+  (unreachable)
+ )
+ (func "export" (param $0 f32) (result funcref)
+  ;; a ref.func should prevent us from changing the type of a function, as it
+  ;; may escape
+  (ref.func $0)
+ )
+)
diff --git a/binaryen/test/passes/dae_enable-tail-call.txt b/binaryen/test/passes/dae_enable-tail-call.txt
deleted file mode 100644
--- a/binaryen/test/passes/dae_enable-tail-call.txt
+++ /dev/null
@@ -1,281 +0,0 @@
-(module
- (type $none_=>_none (func))
- (type $i32_=>_none (func (param i32)))
- (type $none_=>_i32 (func (result i32)))
- (type $f64_=>_none (func (param f64)))
- (table $0 2 2 funcref)
- (elem (i32.const 0) $a9 $c8)
- (export "a8" (func $a8))
- (func $a
-  (local $0 i32)
-  (local.set $0
-   (i32.const 1)
-  )
-  (nop)
- )
- (func $b
-  (call $a)
- )
- (func $a1
-  (local $0 i32)
-  (local.set $0
-   (i32.const 2)
-  )
-  (unreachable)
- )
- (func $b1
-  (call $a1)
- )
- (func $b11
-  (call $a1)
- )
- (func $a2 (param $x i32)
-  (drop
-   (local.get $x)
-  )
- )
- (func $b2
-  (call $a2
-   (i32.const 3)
-  )
- )
- (func $b22
-  (call $a2
-   (i32.const 4)
-  )
- )
- (func $a3
-  (local $0 i32)
-  (drop
-   (i32.const -1)
-  )
- )
- (func $b3
-  (call $a3)
- )
- (func $b33
-  (call $a3)
- )
- (func $a4 (param $x i32)
-  (nop)
- )
- (func $b4
-  (call $a4
-   (unreachable)
-  )
- )
- (func $b43
-  (call $a4
-   (i32.const 4)
-  )
- )
- (func $a5
-  (local $0 f64)
-  (local $1 i32)
-  (local.set $0
-   (f64.const 3.14159)
-  )
-  (block
-   (local.set $1
-    (i32.const 1)
-   )
-   (block
-    (drop
-     (local.get $1)
-    )
-    (drop
-     (local.get $0)
-    )
-   )
-  )
- )
- (func $b5
-  (call $a5)
- )
- (func $a6 (param $0 i32)
-  (local $1 f64)
-  (local.set $1
-   (f64.const 3.14159)
-  )
-  (block
-   (drop
-    (local.get $0)
-   )
-   (drop
-    (local.get $1)
-   )
-  )
- )
- (func $b6
-  (call $a6
-   (unreachable)
-  )
- )
- (func $a7 (param $0 f64)
-  (local $1 i32)
-  (local.set $1
-   (i32.const 1)
-  )
-  (block
-   (drop
-    (local.get $1)
-   )
-   (drop
-    (local.get $0)
-   )
-  )
- )
- (func $b7
-  (call $a7
-   (unreachable)
-  )
- )
- (func $a8 (param $x i32)
-  (nop)
- )
- (func $b8
-  (call $a8
-   (i32.const 1)
-  )
- )
- (func $a9 (param $x i32)
-  (nop)
- )
- (func $b9
-  (call $a9
-   (i32.const 1)
-  )
- )
- (func $a10
-  (local $0 i32)
-  (local.set $0
-   (i32.const 1)
-  )
-  (block
-   (call $a10)
-   (call $a10)
-  )
- )
- (func $a11
-  (local $0 i32)
-  (call $a11)
-  (call $a11)
- )
- (func $a12 (param $x i32)
-  (drop
-   (local.get $x)
-  )
-  (call $a12
-   (i32.const 1)
-  )
-  (call $a12
-   (i32.const 2)
-  )
- )
- (func $c1
-  (local $x i32)
-  (call $c2)
-  (call $c3)
-  (call $c3)
-  (drop
-   (call $c4)
-  )
-  (local.set $x
-   (call $c4)
-  )
-  (call $c5
-   (unreachable)
-  )
-  (call $c6)
-  (call $c7)
-  (drop
-   (call $c8)
-  )
- )
- (func $c2
-  (drop
-   (i32.const 1)
-  )
- )
- (func $c3
-  (drop
-   (i32.const 2)
-  )
- )
- (func $c4 (result i32)
-  (i32.const 3)
- )
- (func $c5 (param $x i32)
-  (drop
-   (local.get $x)
-  )
- )
- (func $c6
-  (unreachable)
- )
- (func $c7
-  (drop
-   (i32.const 4)
-  )
-  (return)
- )
- (func $c8 (result i32)
-  (i32.const 5)
- )
-)
-(module
- (type $none_=>_none (func))
- (export "a" (func $0))
- (func $0
-  (call $b)
- )
- (func $b
-  (local $0 i32)
-  (drop
-   (block (result i32)
-    (local.set $0
-     (i32.const 1)
-    )
-    (local.get $0)
-   )
-  )
- )
-)
-(module
- (type $none_=>_i32 (func (result i32)))
- (type $i32_=>_i32 (func (param i32) (result i32)))
- (func $foo (param $x i32) (result i32)
-  (drop
-   (return_call $bar)
-  )
-  (i32.const 42)
- )
- (func $bar (result i32)
-  (local $0 i32)
-  (local.set $0
-   (i32.const 0)
-  )
-  (i32.const 7)
- )
-)
-(module
- (type $none_=>_i32 (func (result i32)))
- (type $none_=>_none (func))
- (table $0 1 1 funcref)
- (func $foo (result i32)
-  (local $0 i32)
-  (local.set $0
-   (i32.const 42)
-  )
-  (drop
-   (return_call_indirect (type $none_=>_i32)
-    (i32.const 0)
-   )
-  )
- )
- (func $bar
-  (drop
-   (call $foo)
-  )
- )
-)
diff --git a/binaryen/test/passes/dae_enable-tail-call.wast b/binaryen/test/passes/dae_enable-tail-call.wast
deleted file mode 100644
--- a/binaryen/test/passes/dae_enable-tail-call.wast
+++ /dev/null
@@ -1,163 +0,0 @@
-(module
-  (export "a8" (func $a8))
-  (table 2 2 funcref)
-  (elem (i32.const 0) $a9 $c8)
-  (func $a (param $x i32))
-  (func $b
-    (call $a (i32.const 1)) ;; best case scenario
-  )
-  (func $a1 (param $x i32)
-    (unreachable)
-  )
-  (func $b1
-    (call $a1 (i32.const 2)) ;; same value in both, so works
-  )
-  (func $b11
-    (call $a1 (i32.const 2))
-  )
-  (func $a2 (param $x i32)
-    (drop (local.get $x))
-  )
-  (func $b2
-    (call $a2 (i32.const 3)) ;; different value!
-  )
-  (func $b22
-    (call $a2 (i32.const 4))
-  )
-  (func $a3 (param $x i32)
-    (drop (i32.const -1)) ;; diff value, but at least unused, so no need to send
-  )
-  (func $b3
-    (call $a3 (i32.const 3))
-  )
-  (func $b33
-    (call $a3 (i32.const 4))
-  )
-  (func $a4 (param $x i32) ;; diff value, but with effects
-  )
-  (func $b4
-    (call $a4 (unreachable))
-  )
-  (func $b43
-    (call $a4 (i32.const 4))
-  )
-  (func $a5 (param $x i32) (param $y f64) ;; optimize two
-    (drop (local.get $x))
-    (drop (local.get $y))
-  )
-  (func $b5
-    (call $a5 (i32.const 1) (f64.const 3.14159))
-  )
-  (func $a6 (param $x i32) (param $y f64) ;; optimize just one
-    (drop (local.get $x))
-    (drop (local.get $y))
-  )
-  (func $b6
-    (call $a6 (unreachable) (f64.const 3.14159))
-  )
-  (func $a7 (param $x i32) (param $y f64) ;; optimize just the other one
-    (drop (local.get $x))
-    (drop (local.get $y))
-  )
-  (func $b7
-    (call $a7 (i32.const 1) (unreachable))
-  )
-  (func $a8 (param $x i32)) ;; exported, do not optimize
-  (func $b8
-    (call $a8 (i32.const 1))
-  )
-  (func $a9 (param $x i32)) ;; tabled, do not optimize
-  (func $b9
-    (call $a9 (i32.const 1))
-  )
-  (func $a10 (param $x i32) ;; recursion
-    (call $a10 (i32.const 1))
-    (call $a10 (i32.const 1))
-  )
-  (func $a11 (param $x i32) ;; partially successful recursion
-    (call $a11 (i32.const 1))
-    (call $a11 (i32.const 2))
-  )
-  (func $a12 (param $x i32) ;; unsuccessful recursion
-    (drop (local.get $x))
-    (call $a12 (i32.const 1))
-    (call $a12 (i32.const 2))
-  )
-  ;; return values
-  (func $c1
-    (local $x i32)
-    (drop (call $c2))
-    (drop (call $c3))
-    (drop (call $c3))
-    (drop (call $c4))
-    (local.set $x (call $c4))
-    (drop (call $c5 (unreachable)))
-    (drop (call $c6))
-    (drop (call $c7))
-    (drop (call $c8))
-  )
-  (func $c2 (result i32)
-    (i32.const 1)
-  )
-  (func $c3 (result i32)
-    (i32.const 2)
-  )
-  (func $c4 (result i32)
-    (i32.const 3)
-  )
-  (func $c5 (param $x i32) (result i32)
-    (local.get $x)
-  )
-  (func $c6 (result i32)
-    (unreachable)
-  )
-  (func $c7 (result i32)
-    (return (i32.const 4))
-  )
-  (func $c8 (result i32)
-    (i32.const 5)
-  )
-)
-(module ;; both operations at once: remove params and return value
-  (func "a"
-    (drop
-      (call $b
-        (i32.const 1)
-      )
-    )
-  )
-  (func $b (param $x i32) (result i32)
-    (local.get $x)
-  )
-)
-(module ;; tail calls inhibit dropped result removal
-  (func $foo (param $x i32) (result i32)
-    (drop
-      (return_call $bar
-        (i32.const 0)
-      )
-    )
-    (i32.const 42)
-  )
-  (func $bar (param $x i32) (result i32)
-    (i32.const 7)
-  )
-)
-(module ;; indirect tail calls inhibit dropped result removal
-  (type $T (func (result i32)))
-  (table 1 1 funcref)
-  (func $foo (param $x i32) (result i32)
-    (drop
-      (return_call_indirect (type $T)
-        (i32.const 0)
-      )
-    )
-  )
-  (func $bar
-    (drop
-      (call $foo
-        (i32.const 42)
-      )
-    )
-  )
-)
diff --git a/binaryen/test/passes/dce_all-features.txt b/binaryen/test/passes/dce_all-features.txt
--- a/binaryen/test/passes/dce_all-features.txt
+++ b/binaryen/test/passes/dce_all-features.txt
@@ -24,7 +24,9 @@
   )
   (if
    (i32.const 0)
-   (return)
+   (block $out3
+    (return)
+   )
   )
   (block $out4
    (br_table $out4 $out4 $out4 $out4
@@ -41,10 +43,12 @@
   )
   (if
    (i32.const 0)
-   (if
-    (i32.const 0)
-    (unreachable)
-    (unreachable)
+   (block $block4
+    (if
+     (i32.const 0)
+     (unreachable)
+     (unreachable)
+    )
    )
   )
   (if
@@ -69,13 +73,15 @@
   )
   (if
    (i32.const 0)
-   (block $out18
-    (block $in19
-     (br_if $in19
-      (i32.const 1)
+   (block $block11
+    (block $out18
+     (block $in19
+      (br_if $in19
+       (i32.const 1)
+      )
      )
+     (unreachable)
     )
-    (unreachable)
    )
   )
   (block $out20
@@ -96,13 +102,15 @@
   )
   (if
    (i32.const 0)
-   (block $out25
-    (block $in26
-     (br_table $in26 $in26
-      (i32.const 1)
+   (block $block13
+    (block $out25
+     (block $in26
+      (br_table $in26 $in26
+       (i32.const 1)
+      )
      )
+     (unreachable)
     )
-    (unreachable)
    )
   )
   (if
@@ -122,7 +130,7 @@
    (unreachable)
   )
   (block $out29
-   (block
+   (loop $in30
     (br_if $out29
      (i32.const 1)
     )
@@ -131,11 +139,13 @@
   )
   (if
    (i32.const 0)
-   (loop $in32
-    (br_if $in32
-     (i32.const 1)
+   (block $block20
+    (loop $in32
+     (br_if $in32
+      (i32.const 1)
+     )
+     (unreachable)
     )
-    (unreachable)
    )
   )
   (if
@@ -273,8 +283,12 @@
   )
  )
  (func $typed-block-none-then-unreachable (result i32)
-  (return
-   (i32.const 0)
+  (block $top-typed
+   (block $switch$0
+    (return
+     (i32.const 0)
+    )
+   )
   )
  )
  (func $typed-block-remove-br-changes-type (param $$$0 i32) (result i32)
@@ -317,15 +331,19 @@
   )
  )
  (func $unreachable-block-ends-switch (result i32)
-  (block $label$3
-   (nop)
-   (unreachable)
+  (block $label$0
+   (block $label$3
+    (nop)
+    (unreachable)
+   )
   )
  )
  (func $unreachable-block-ends-br_if (result i32)
-  (block $label$2
-   (nop)
-   (unreachable)
+  (block $label$0
+   (block $label$2
+    (nop)
+    (unreachable)
+   )
   )
  )
  (func $unreachable-brs-3 (result i32)
@@ -339,11 +357,15 @@
   (drop
    (i32.const 1)
   )
-  (block
-   (drop
-    (i32.const 4104)
+  (block $label$0
+   (block $label$1
+    (block
+     (drop
+      (i32.const 4104)
+     )
+     (unreachable)
+    )
    )
-   (unreachable)
   )
  )
  (func $call-unreach (param $var$0 i64) (param $var$1 i64) (result i64)
@@ -355,32 +377,36 @@
    (block $label$0 (result i64)
     (local.get $var$1)
    )
-   (block
-    (drop
-     (i64.sub
-      (local.get $var$0)
-      (i64.const 1)
-     )
-    )
+   (block $label$1
     (block
      (drop
-      (block $block (result i64)
-       (local.set $2
-        (local.get $var$0)
+      (i64.sub
+       (local.get $var$0)
+       (i64.const 1)
+      )
+     )
+     (block
+      (drop
+       (block $block (result i64)
+        (local.set $2
+         (local.get $var$0)
+        )
+        (nop)
+        (local.get $2)
        )
-       (nop)
-       (local.get $2)
       )
+      (unreachable)
      )
-     (unreachable)
     )
    )
   )
  )
  (func $br-gone-means-block-type-changes-then-refinalize-at-end-is-too-late (param $var$0 i32) (result i32)
-  (block $block
-   (nop)
-   (unreachable)
+  (block $label$0
+   (block $block
+    (nop)
+    (unreachable)
+   )
   )
  )
  (func $br-with-unreachable-value-should-not-give-a-block-a-value (param $var$0 i32) (result i32)
@@ -397,25 +423,31 @@
   )
  )
  (func $replace-br-value-of-i32-with-unreachable (result i32)
-  (block $label$1
-   (nop)
-   (unreachable)
+  (block $label$0
+   (block $label$1
+    (nop)
+    (unreachable)
+   )
   )
  )
  (func $shorten-block-requires-sync-refinalize (param $var$0 i32) (param $var$1 i32)
   (unreachable)
  )
  (func $block-with-type-but-is-unreachable (param $var$0 i32) (result i32)
-  (block $block
-   (nop)
-   (unreachable)
+  (block $label$0
+   (block $block
+    (nop)
+    (unreachable)
+   )
   )
  )
  (func $if-with-type-but-is-unreachable (param $var$0 i32) (result i32)
-  (if
-   (local.get $var$0)
-   (unreachable)
-   (unreachable)
+  (block $label$0
+   (if
+    (local.get $var$0)
+    (unreachable)
+    (unreachable)
+   )
   )
  )
  (func $unreachable-loop
@@ -423,8 +455,10 @@
  )
  (func $br-block-from-unary (result i32)
   (block $label$6 (result i32)
-   (br $label$6
-    (i32.const 8)
+   (block $label$7
+    (br $label$6
+     (i32.const 8)
+    )
    )
   )
  )
@@ -444,19 +478,23 @@
   )
  )
  (func $replace-with-unreachable-affects-parent (param $var$0 f32) (param $var$1 i64)
-  (drop
-   (i64.const 0)
-  )
-  (if
-   (block $block (result i32)
-    (call $replace-with-unreachable-affects-parent
-     (f32.const 1)
-     (i64.const -15917430362925035)
+  (block $top
+   (block
+    (drop
+     (i64.const 0)
     )
-    (i32.const 1)
+    (if
+     (block $block (result i32)
+      (call $replace-with-unreachable-affects-parent
+       (f32.const 1)
+       (i64.const -15917430362925035)
+      )
+      (i32.const 1)
+     )
+     (unreachable)
+     (unreachable)
+    )
    )
-   (unreachable)
-   (unreachable)
   )
  )
  (func $replace-block-changes-later-when-if-goes
@@ -503,6 +541,7 @@
 )
 (module
  (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
  (event $e (attr 0) (param))
  (func $foo
   (nop)
@@ -542,12 +581,68 @@
   )
  )
  (func $throw
-  (throw $e
+  (block $label$0
+   (block $label$1
+    (throw $e
+    )
+   )
   )
  )
  (func $rethrow
-  (rethrow
-   (ref.null exn)
+  (block $label$0
+   (block $label$1
+    (rethrow
+     (ref.null exn)
+    )
+   )
+  )
+ )
+ (func $unnecessary-concrete-block (result i32)
+  (block $foo
+   (nop)
+   (unreachable)
+  )
+ )
+ (func $necessary-concrete-block (result i32)
+  (block $foo (result i32)
+   (br $foo
+    (i32.const 1)
+   )
+  )
+ )
+ (func $unnecessary-concrete-if (result i32)
+  (if
+   (i32.const 0)
+   (return
+    (i32.const 1)
+   )
+   (unreachable)
+  )
+ )
+ (func $unnecessary-concrete-try (result i32)
+  (try
+   (do
+    (unreachable)
+   )
+   (catch
+    (unreachable)
+   )
+  )
+ )
+ (func $note-loss-of-if-children
+  (block $label$1
+   (block $label$2
+    (nop)
+    (unreachable)
+   )
+  )
+ )
+ (func $note-loss-of-non-control-flow-children
+  (block $out
+   (block $block
+    (nop)
+    (unreachable)
+   )
   )
  )
 )
diff --git a/binaryen/test/passes/dce_all-features.wast b/binaryen/test/passes/dce_all-features.wast
--- a/binaryen/test/passes/dce_all-features.wast
+++ b/binaryen/test/passes/dce_all-features.wast
@@ -810,4 +810,61 @@
       )
     )
   )
+
+  (func $unnecessary-concrete-block (result i32)
+    (block $foo (result i32) ;; unnecessary type
+      (nop)
+      (unreachable)
+    )
+  )
+  (func $necessary-concrete-block (result i32)
+    (block $foo (result i32)
+      (br $foo (i32.const 1))
+      (unreachable)
+    )
+  )
+  (func $unnecessary-concrete-if (result i32)
+    (if (result i32) ;; unnecessary type
+      (i32.const 0)
+      (return (i32.const 1))
+      (unreachable)
+    )
+  )
+  (func $unnecessary-concrete-try (result i32)
+    (try (result i32)
+      (do
+        (unreachable)
+      )
+      (catch
+        (unreachable)
+      )
+    )
+  )
+  (func $note-loss-of-if-children
+    (block $label$1
+     (if ;; begins unreachable - type never changes - but after the condition
+         ;; becomes unreachable, it will lose the children, which means no more
+         ;; br to the outer block, changing that type.
+       (block $label$2 (result i32)
+         (nop)
+         (unreachable)
+       )
+       (unreachable)
+       (br $label$1)
+      )
+    )
+  )
+  (func $note-loss-of-non-control-flow-children
+    (block $out
+      (drop
+       (i32.add
+         (block (result i32)
+            (nop)
+            (unreachable)
+         )
+         (br $out) ;; when this is removed as dead, the block becomes unreachable
+       )
+     )
+    )
+  )
 )
diff --git a/binaryen/test/passes/dce_vacuum.bin.txt b/binaryen/test/passes/dce_vacuum.bin.txt
deleted file mode 100644
--- a/binaryen/test/passes/dce_vacuum.bin.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-(module
- (type $f32_f32_=>_f32 (func (param f32 f32) (result f32)))
- (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
- (export "f32.compute_radix" (func $0))
- (export "f64.compute_radix" (func $1))
- (func $0 (param $0 f32) (param $1 f32) (result f32)
-  (block $label$1
-   (loop $label$2
-    (br_if $label$2
-     (f32.eq
-      (f32.add
-       (f32.sub
-        (f32.add
-         (local.tee $0
-          (f32.add
-           (local.get $0)
-           (local.get $0)
-          )
-         )
-         (f32.const 1)
-        )
-        (local.get $0)
-       )
-       (f32.const -1)
-      )
-      (f32.const 0)
-     )
-    )
-   )
-   (block
-    (drop
-     (call $0
-      (f32.add
-       (local.get $0)
-       (local.tee $1
-        (f32.add
-         (local.get $1)
-         (f32.const 1)
-        )
-       )
-      )
-      (local.get $0)
-     )
-    )
-    (unreachable)
-   )
-  )
- )
- (func $1 (param $0 f64) (param $1 f64) (result f64)
-  (block $label$1 (result f64)
-   (loop $label$2
-    (br_if $label$2
-     (f64.eq
-      (f64.add
-       (f64.sub
-        (f64.add
-         (local.tee $0
-          (f64.add
-           (local.get $0)
-           (local.get $0)
-          )
-         )
-         (f64.const 1)
-        )
-        (local.get $0)
-       )
-       (f64.const -1)
-      )
-      (f64.const 0)
-     )
-    )
-   )
-   (loop $label$3
-    (br_if $label$3
-     (f64.ne
-      (f64.sub
-       (f64.sub
-        (f64.add
-         (local.get $0)
-         (local.tee $1
-          (f64.add
-           (local.get $1)
-           (f64.const 1)
-          )
-         )
-        )
-        (local.get $0)
-       )
-       (local.get $1)
-      )
-      (f64.const 0)
-     )
-    )
-   )
-   (local.get $1)
-  )
- )
-)
diff --git a/binaryen/test/passes/dce_vacuum.txt b/binaryen/test/passes/dce_vacuum.txt
deleted file mode 100644
--- a/binaryen/test/passes/dce_vacuum.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-(module
- (type $none_=>_i32 (func (result i32)))
- (type $i64_=>_i64 (func (param i64) (result i64)))
- (type $f32_f32_=>_f32 (func (param f32 f32) (result f32)))
- (func $__Z12serveroptionPc (result i32)
-  (return
-   (i32.const 0)
-  )
- )
- (func $drop-unreachable (param $var$0 f32) (param $var$1 f32) (result f32)
-  (unreachable)
- )
- (func $set-unreachable (param $var$0 i64) (result i64)
-  (local $var$1 i64)
-  (local $var$2 i64)
-  (if
-   (i64.eq
-    (local.get $var$1)
-    (i64.const 0)
-   )
-   (unreachable)
-   (unreachable)
-  )
- )
-)
diff --git a/binaryen/test/passes/dce_vacuum.wasm b/binaryen/test/passes/dce_vacuum.wasm
deleted file mode 100644
Binary files a/binaryen/test/passes/dce_vacuum.wasm and /dev/null differ
diff --git a/binaryen/test/passes/dce_vacuum.wast b/binaryen/test/passes/dce_vacuum.wast
deleted file mode 100644
--- a/binaryen/test/passes/dce_vacuum.wast
+++ /dev/null
@@ -1,51 +0,0 @@
-(module
-  (func $__Z12serveroptionPc (result i32)
-    (block $switch$0
-      (return
-        (i32.const 0)
-      )
-      (br $switch$0)
-    )
-    (return
-      (i32.const 0)
-    )
-  )
-  (func $drop-unreachable (param $var$0 f32) (param $var$1 f32) (result f32)
-   (block $label$0 (result f32)
-    (loop $label$2
-     (drop
-      (unreachable)
-     )
-     (unreachable)
-    )
-    (local.get $var$1)
-   )
-  )
-
- (func $set-unreachable (param $var$0 i64) (result i64)
-  (local $var$1 i64)
-  (local $var$2 i64)
-  (block $label$0 (result i64)
-   (block $label$1
-    (loop $label$2
-     (if
-      (i64.eq
-       (local.get $var$1)
-       (i64.const 0)
-      )
-      (unreachable)
-      (local.set $var$2
-       (i64.mul
-        (unreachable)
-        (local.get $var$2)
-       )
-      )
-     )
-     (br $label$2)
-    )
-   )
-   (local.get $var$2)
-  )
- )
-)
-
diff --git a/binaryen/test/passes/dce_vacuum_remove-unused-names.bin.txt b/binaryen/test/passes/dce_vacuum_remove-unused-names.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dce_vacuum_remove-unused-names.bin.txt
@@ -0,0 +1,94 @@
+(module
+ (type $f32_f32_=>_f32 (func (param f32 f32) (result f32)))
+ (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
+ (export "f32.compute_radix" (func $0))
+ (export "f64.compute_radix" (func $1))
+ (func $0 (param $0 f32) (param $1 f32) (result f32)
+  (loop $label$2
+   (br_if $label$2
+    (f32.eq
+     (f32.add
+      (f32.sub
+       (f32.add
+        (local.tee $0
+         (f32.add
+          (local.get $0)
+          (local.get $0)
+         )
+        )
+        (f32.const 1)
+       )
+       (local.get $0)
+      )
+      (f32.const -1)
+     )
+     (f32.const 0)
+    )
+   )
+  )
+  (block
+   (drop
+    (call $0
+     (f32.add
+      (local.get $0)
+      (local.tee $1
+       (f32.add
+        (local.get $1)
+        (f32.const 1)
+       )
+      )
+     )
+     (local.get $0)
+    )
+   )
+   (unreachable)
+  )
+ )
+ (func $1 (param $0 f64) (param $1 f64) (result f64)
+  (loop $label$2
+   (br_if $label$2
+    (f64.eq
+     (f64.add
+      (f64.sub
+       (f64.add
+        (local.tee $0
+         (f64.add
+          (local.get $0)
+          (local.get $0)
+         )
+        )
+        (f64.const 1)
+       )
+       (local.get $0)
+      )
+      (f64.const -1)
+     )
+     (f64.const 0)
+    )
+   )
+  )
+  (loop $label$3
+   (br_if $label$3
+    (f64.ne
+     (f64.sub
+      (f64.sub
+       (f64.add
+        (local.get $0)
+        (local.tee $1
+         (f64.add
+          (local.get $1)
+          (f64.const 1)
+         )
+        )
+       )
+       (local.get $0)
+      )
+      (local.get $1)
+     )
+     (f64.const 0)
+    )
+   )
+  )
+  (local.get $1)
+ )
+)
diff --git a/binaryen/test/passes/dce_vacuum_remove-unused-names.txt b/binaryen/test/passes/dce_vacuum_remove-unused-names.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dce_vacuum_remove-unused-names.txt
@@ -0,0 +1,25 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (type $i64_=>_i64 (func (param i64) (result i64)))
+ (type $f32_f32_=>_f32 (func (param f32 f32) (result f32)))
+ (func $__Z12serveroptionPc (result i32)
+  (return
+   (i32.const 0)
+  )
+ )
+ (func $drop-unreachable (param $var$0 f32) (param $var$1 f32) (result f32)
+  (unreachable)
+ )
+ (func $set-unreachable (param $var$0 i64) (result i64)
+  (local $var$1 i64)
+  (local $var$2 i64)
+  (if
+   (i64.eq
+    (local.get $var$1)
+    (i64.const 0)
+   )
+   (unreachable)
+   (unreachable)
+  )
+ )
+)
diff --git a/binaryen/test/passes/dce_vacuum_remove-unused-names.wasm b/binaryen/test/passes/dce_vacuum_remove-unused-names.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/dce_vacuum_remove-unused-names.wasm differ
diff --git a/binaryen/test/passes/dce_vacuum_remove-unused-names.wast b/binaryen/test/passes/dce_vacuum_remove-unused-names.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/dce_vacuum_remove-unused-names.wast
@@ -0,0 +1,51 @@
+(module
+  (func $__Z12serveroptionPc (result i32)
+    (block $switch$0
+      (return
+        (i32.const 0)
+      )
+      (br $switch$0)
+    )
+    (return
+      (i32.const 0)
+    )
+  )
+  (func $drop-unreachable (param $var$0 f32) (param $var$1 f32) (result f32)
+   (block $label$0 (result f32)
+    (loop $label$2
+     (drop
+      (unreachable)
+     )
+     (unreachable)
+    )
+    (local.get $var$1)
+   )
+  )
+
+ (func $set-unreachable (param $var$0 i64) (result i64)
+  (local $var$1 i64)
+  (local $var$2 i64)
+  (block $label$0 (result i64)
+   (block $label$1
+    (loop $label$2
+     (if
+      (i64.eq
+       (local.get $var$1)
+       (i64.const 0)
+      )
+      (unreachable)
+      (local.set $var$2
+       (i64.mul
+        (unreachable)
+        (local.get $var$2)
+       )
+      )
+     )
+     (br $label$2)
+    )
+   )
+   (local.get $var$2)
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/directize_all-features.txt b/binaryen/test/passes/directize_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/directize_all-features.txt
@@ -0,0 +1,223 @@
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call $foo
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 4) $foo)
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call $foo
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call $foo
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 0) $foo $foo $foo $foo $foo)
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call $foo
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (import "env" "table" (table $table 5 5 funcref))
+ (elem (i32.const 1) $foo)
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $i32_i32_=>_none)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (export "tab" (table $0))
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $i32_i32_=>_none)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (global.get $g) $foo)
+ (global $g (mut i32) (i32.const 1))
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $i32_i32_=>_none)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 1)
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32) (param $z i32)
+  (call_indirect (type $i32_i32_=>_none)
+   (local.get $x)
+   (local.get $y)
+   (local.get $z)
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (block
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+  (unreachable)
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (block
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+  (unreachable)
+ )
+)
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param $0 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (block
+   (drop
+    (local.get $x)
+   )
+   (drop
+    (local.get $y)
+   )
+  )
+  (unreachable)
+ )
+)
+(module
+ (type $i32_=>_none (func (param i32)))
+ (func $foo (param $0 i32)
+  (unreachable)
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (table $0 8 8 funcref)
+ (func $0
+  (block $block
+   (nop)
+   (block
+    (block
+    )
+    (unreachable)
+   )
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (return_call $foo
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+)
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (func $foo (param $0 i32) (param $1 i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call $foo
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+)
diff --git a/binaryen/test/passes/directize_all-features.wast b/binaryen/test/passes/directize_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/directize_all-features.wast
@@ -0,0 +1,223 @@
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 1)
+  )
+ )
+)
+;; at table edges
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 4) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 4)
+  )
+ )
+)
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 0) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 0)
+  )
+ )
+)
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 0) $foo $foo $foo $foo $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 2)
+  )
+ )
+)
+;; imported table
+(module
+ (type $ii (func (param i32 i32)))
+ (import "env" "table" (table $table 5 5 funcref))
+ (elem (i32.const 1) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 1)
+  )
+ )
+)
+;; exported table
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (export "tab" (table $0))
+ (elem (i32.const 1) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 1)
+  )
+ )
+)
+;; non-constant table offset
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (global $g (mut i32) (i32.const 1))
+ (elem (global.get $g) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 1)
+  )
+ )
+)
+;; non-constant call index
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32) (param $z i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (local.get $z)
+  )
+ )
+)
+;; bad index
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 5)
+  )
+ )
+)
+;; missing index
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 2)
+  )
+ )
+)
+;; bad type
+(module
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 1)
+  )
+ )
+)
+;; no table
+(module
+ (func $foo (param i32)
+  (unreachable)
+ )
+)
+;; change types
+(module
+ (type (func))
+ (table $0 8 8 funcref)
+ (func $0
+  (block ;; the type of this block will change
+   (nop)
+   (call_indirect (type 0)
+    (i32.const 15)
+   )
+  )
+ )
+)
+(module ;; indirect tail call
+ (type $ii (func (param i32 i32)))
+ (table $0 5 5 funcref)
+ (elem (i32.const 1) $foo)
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (return_call_indirect (type $ii)
+   (local.get $x)
+   (local.get $y)
+   (i32.const 1)
+  )
+ )
+)
+;; call_ref
+(module
+ (func $foo (param i32) (param i32)
+  (unreachable)
+ )
+ (func $bar (param $x i32) (param $y i32)
+  (call_ref
+   (local.get $x)
+   (local.get $y)
+   (ref.func $foo)
+  )
+ )
+)
+
diff --git a/binaryen/test/passes/directize_enable-tail-call.txt b/binaryen/test/passes/directize_enable-tail-call.txt
deleted file mode 100644
--- a/binaryen/test/passes/directize_enable-tail-call.txt
+++ /dev/null
@@ -1,211 +0,0 @@
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call $foo
-   (local.get $x)
-   (local.get $y)
-  )
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 4) $foo)
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call $foo
-   (local.get $x)
-   (local.get $y)
-  )
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 0) $foo)
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call $foo
-   (local.get $x)
-   (local.get $y)
-  )
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 0) $foo $foo $foo $foo $foo)
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call $foo
-   (local.get $x)
-   (local.get $y)
-  )
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (import "env" "table" (table $table 5 5 funcref))
- (elem (i32.const 1) $foo)
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $i32_i32_=>_none)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 1)
-  )
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (export "tab" (table $0))
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $i32_i32_=>_none)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 1)
-  )
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (global.get $g) $foo)
- (global $g (mut i32) (i32.const 1))
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $i32_i32_=>_none)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 1)
-  )
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32) (param $z i32)
-  (call_indirect (type $i32_i32_=>_none)
-   (local.get $x)
-   (local.get $y)
-   (local.get $z)
-  )
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (block
-   (drop
-    (local.get $x)
-   )
-   (drop
-    (local.get $y)
-   )
-  )
-  (unreachable)
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (block
-   (drop
-    (local.get $x)
-   )
-   (drop
-    (local.get $y)
-   )
-  )
-  (unreachable)
- )
-)
-(module
- (type $i32_=>_none (func (param i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param $0 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (block
-   (drop
-    (local.get $x)
-   )
-   (drop
-    (local.get $y)
-   )
-  )
-  (unreachable)
- )
-)
-(module
- (type $i32_=>_none (func (param i32)))
- (func $foo (param $0 i32)
-  (unreachable)
- )
-)
-(module
- (type $none_=>_none (func))
- (table $0 8 8 funcref)
- (func $0
-  (block $block
-   (nop)
-   (block
-    (block
-    )
-    (unreachable)
-   )
-  )
- )
-)
-(module
- (type $i32_i32_=>_none (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param $0 i32) (param $1 i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (return_call $foo
-   (local.get $x)
-   (local.get $y)
-  )
- )
-)
diff --git a/binaryen/test/passes/directize_enable-tail-call.wast b/binaryen/test/passes/directize_enable-tail-call.wast
deleted file mode 100644
--- a/binaryen/test/passes/directize_enable-tail-call.wast
+++ /dev/null
@@ -1,209 +0,0 @@
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 1)
-  )
- )
-)
-;; at table edges
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 4) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 4)
-  )
- )
-)
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 0) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 0)
-  )
- )
-)
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 0) $foo $foo $foo $foo $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 2)
-  )
- )
-)
-;; imported table
-(module
- (type $ii (func (param i32 i32)))
- (import "env" "table" (table $table 5 5 funcref))
- (elem (i32.const 1) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 1)
-  )
- )
-)
-;; exported table
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (export "tab" (table $0))
- (elem (i32.const 1) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 1)
-  )
- )
-)
-;; non-constant table offset
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (global $g (mut i32) (i32.const 1))
- (elem (global.get $g) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 1)
-  )
- )
-)
-;; non-constant call index
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32) (param $z i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (local.get $z)
-  )
- )
-)
-;; bad index
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 5)
-  )
- )
-)
-;; missing index
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 2)
-  )
- )
-)
-;; bad type
-(module
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 1)
-  )
- )
-)
-;; no table
-(module
- (func $foo (param i32)
-  (unreachable)
- )
-)
-;; change types
-(module
- (type (func))
- (table $0 8 8 funcref)
- (func $0
-  (block ;; the type of this block will change
-   (nop)
-   (call_indirect (type 0)
-    (i32.const 15)
-   )
-  )
- )
-)
-(module ;; indirect tail call
- (type $ii (func (param i32 i32)))
- (table $0 5 5 funcref)
- (elem (i32.const 1) $foo)
- (func $foo (param i32) (param i32)
-  (unreachable)
- )
- (func $bar (param $x i32) (param $y i32)
-  (return_call_indirect (type $ii)
-   (local.get $x)
-   (local.get $y)
-   (i32.const 1)
-  )
- )
-)
diff --git a/binaryen/test/passes/fannkuch0_dwarf.bin.txt b/binaryen/test/passes/fannkuch0_dwarf.bin.txt
--- a/binaryen/test/passes/fannkuch0_dwarf.bin.txt
+++ b/binaryen/test/passes/fannkuch0_dwarf.bin.txt
@@ -5197,7 +5197,7 @@
  (type $i32_=>_none (func (param i32)))
  (import "env" "memory" (memory $mimport$0 256 256))
  (data (i32.const 1024) "Wrong argument.\n\00Pfannkuchen(%d) = %d.\n\00%d\00\n\00")
- (import "env" "__indirect_function_table" (table $timport$1 1 funcref))
+ (import "env" "__indirect_function_table" (table $timport$0 1 funcref))
  (import "env" "malloc" (func $malloc (param i32) (result i32)))
  (import "env" "free" (func $free (param i32)))
  (import "env" "atoi" (func $atoi (param i32) (result i32)))
diff --git a/binaryen/test/passes/fannkuch3_dwarf.bin.txt b/binaryen/test/passes/fannkuch3_dwarf.bin.txt
--- a/binaryen/test/passes/fannkuch3_dwarf.bin.txt
+++ b/binaryen/test/passes/fannkuch3_dwarf.bin.txt
@@ -2851,7 +2851,7 @@
 0x00000278:     DW_TAG_inlined_subroutine [24] *
                   DW_AT_abstract_origin [DW_FORM_ref4]	(cu + 0x01a8 => {0x000001a8} "_ZL8fannkuchi")
                   DW_AT_low_pc [DW_FORM_addr]	(0x00000000000003ec)
-                  DW_AT_high_pc [DW_FORM_data4]	(0x0000026c)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x0000029e)
                   DW_AT_call_file [DW_FORM_data1]	("/usr/local/google/home/azakai/Dev/emscripten/tests/fannkuch.cpp")
                   DW_AT_call_line [DW_FORM_data1]	(159)
                   DW_AT_call_column [DW_FORM_data1]	(0x29)
@@ -4797,7 +4797,7 @@
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 256 256))
  (data (i32.const 1024) "Pfannkuchen(%d) = %d.\n\00%d\00Wrong argument.\00")
- (import "env" "__indirect_function_table" (table $timport$1 1 funcref))
+ (import "env" "__indirect_function_table" (table $timport$0 1 funcref))
  (import "env" "malloc" (func $malloc (param i32) (result i32)))
  (import "env" "memcpy" (func $memcpy (param i32 i32 i32) (result i32)))
  (import "env" "free" (func $free (param i32)))
diff --git a/binaryen/test/passes/fannkuch3_manyopts_dwarf.bin.txt b/binaryen/test/passes/fannkuch3_manyopts_dwarf.bin.txt
--- a/binaryen/test/passes/fannkuch3_manyopts_dwarf.bin.txt
+++ b/binaryen/test/passes/fannkuch3_manyopts_dwarf.bin.txt
@@ -2303,7 +2303,7 @@
 Contains section .debug_loc (1073 bytes)
 Contains section .debug_ranges (88 bytes)
 Contains section .debug_abbrev (333 bytes)
-Contains section .debug_line (2702 bytes)
+Contains section .debug_line (2682 bytes)
 Contains section .debug_str (434 bytes)
 
 .debug_abbrev contents:
@@ -3119,7 +3119,7 @@
 .debug_line contents:
 debug_line[0x00000000]
 Line table prologue:
-    total_length: 0x00000a8a
+    total_length: 0x00000a76
          version: 4
  prologue_length: 0x000000dd
  min_inst_length: 1
@@ -4364,299 +4364,287 @@
             0x0000000000000547    122     14      1   0             0 
 
 
-0x000008a5: 00 DW_LNE_set_address (0x000000000000054c)
-0x000008ac: 03 DW_LNS_advance_line (130)
-0x000008ae: 06 DW_LNS_negate_stmt
-0x000008af: 01 DW_LNS_copy
-            0x000000000000054c    130     14      1   0             0  is_stmt
-
-
-0x000008b0: 00 DW_LNE_set_address (0x000000000000054d)
-0x000008b7: 03 DW_LNS_advance_line (110)
-0x000008b9: 05 DW_LNS_set_column (11)
-0x000008bb: 01 DW_LNS_copy
+0x000008a5: 00 DW_LNE_set_address (0x000000000000054d)
+0x000008ac: 03 DW_LNS_advance_line (110)
+0x000008ae: 05 DW_LNS_set_column (11)
+0x000008b0: 06 DW_LNS_negate_stmt
+0x000008b1: 01 DW_LNS_copy
             0x000000000000054d    110     11      1   0             0  is_stmt
 
 
-0x000008bc: 00 DW_LNE_set_address (0x0000000000000559)
-0x000008c3: 03 DW_LNS_advance_line (113)
-0x000008c5: 05 DW_LNS_set_column (10)
-0x000008c7: 01 DW_LNS_copy
+0x000008b2: 00 DW_LNE_set_address (0x0000000000000559)
+0x000008b9: 03 DW_LNS_advance_line (113)
+0x000008bb: 05 DW_LNS_set_column (10)
+0x000008bd: 01 DW_LNS_copy
             0x0000000000000559    113     10      1   0             0  is_stmt
 
 
-0x000008c8: 00 DW_LNE_set_address (0x000000000000055c)
-0x000008cf: 03 DW_LNS_advance_line (118)
-0x000008d1: 05 DW_LNS_set_column (16)
-0x000008d3: 01 DW_LNS_copy
+0x000008be: 00 DW_LNE_set_address (0x000000000000055c)
+0x000008c5: 03 DW_LNS_advance_line (118)
+0x000008c7: 05 DW_LNS_set_column (16)
+0x000008c9: 01 DW_LNS_copy
             0x000000000000055c    118     16      1   0             0  is_stmt
 
 
-0x000008d4: 00 DW_LNE_set_address (0x0000000000000565)
-0x000008db: 03 DW_LNS_advance_line (119)
-0x000008dd: 05 DW_LNS_set_column (10)
-0x000008df: 01 DW_LNS_copy
+0x000008ca: 00 DW_LNE_set_address (0x0000000000000565)
+0x000008d1: 03 DW_LNS_advance_line (119)
+0x000008d3: 05 DW_LNS_set_column (10)
+0x000008d5: 01 DW_LNS_copy
             0x0000000000000565    119     10      1   0             0  is_stmt
 
 
-0x000008e0: 00 DW_LNE_set_address (0x0000000000000567)
-0x000008e7: 05 DW_LNS_set_column (18)
-0x000008e9: 06 DW_LNS_negate_stmt
-0x000008ea: 01 DW_LNS_copy
+0x000008d6: 00 DW_LNE_set_address (0x0000000000000567)
+0x000008dd: 05 DW_LNS_set_column (18)
+0x000008df: 06 DW_LNS_negate_stmt
+0x000008e0: 01 DW_LNS_copy
             0x0000000000000567    119     18      1   0             0 
 
 
-0x000008eb: 00 DW_LNE_set_address (0x0000000000000570)
-0x000008f2: 05 DW_LNS_set_column (10)
-0x000008f4: 01 DW_LNS_copy
+0x000008e1: 00 DW_LNE_set_address (0x0000000000000570)
+0x000008e8: 05 DW_LNS_set_column (10)
+0x000008ea: 01 DW_LNS_copy
             0x0000000000000570    119     10      1   0             0 
 
 
-0x000008f5: 00 DW_LNE_set_address (0x0000000000000572)
-0x000008fc: 05 DW_LNS_set_column (23)
-0x000008fe: 01 DW_LNS_copy
+0x000008eb: 00 DW_LNE_set_address (0x0000000000000572)
+0x000008f2: 05 DW_LNS_set_column (23)
+0x000008f4: 01 DW_LNS_copy
             0x0000000000000572    119     23      1   0             0 
 
 
-0x000008ff: 00 DW_LNE_set_address (0x0000000000000577)
-0x00000906: 03 DW_LNS_advance_line (118)
-0x00000908: 05 DW_LNS_set_column (16)
-0x0000090a: 06 DW_LNS_negate_stmt
-0x0000090b: 01 DW_LNS_copy
+0x000008f5: 00 DW_LNE_set_address (0x0000000000000577)
+0x000008fc: 03 DW_LNS_advance_line (118)
+0x000008fe: 05 DW_LNS_set_column (16)
+0x00000900: 06 DW_LNS_negate_stmt
+0x00000901: 01 DW_LNS_copy
             0x0000000000000577    118     16      1   0             0  is_stmt
 
 
-0x0000090c: 00 DW_LNE_set_address (0x0000000000000582)
-0x00000913: 05 DW_LNS_set_column (7)
-0x00000915: 06 DW_LNS_negate_stmt
-0x00000916: 01 DW_LNS_copy
+0x00000902: 00 DW_LNE_set_address (0x0000000000000582)
+0x00000909: 05 DW_LNS_set_column (7)
+0x0000090b: 06 DW_LNS_negate_stmt
+0x0000090c: 01 DW_LNS_copy
             0x0000000000000582    118      7      1   0             0 
 
 
-0x00000917: 00 DW_LNE_set_address (0x0000000000000588)
-0x0000091e: 03 DW_LNS_advance_line (122)
-0x00000920: 05 DW_LNS_set_column (16)
-0x00000922: 06 DW_LNS_negate_stmt
-0x00000923: 01 DW_LNS_copy
+0x0000090d: 00 DW_LNE_set_address (0x0000000000000588)
+0x00000914: 03 DW_LNS_advance_line (122)
+0x00000916: 05 DW_LNS_set_column (16)
+0x00000918: 06 DW_LNS_negate_stmt
+0x00000919: 01 DW_LNS_copy
             0x0000000000000588    122     16      1   0             0  is_stmt
 
 
-0x00000924: 00 DW_LNE_set_address (0x000000000000058d)
-0x0000092b: 05 DW_LNS_set_column (14)
-0x0000092d: 06 DW_LNS_negate_stmt
-0x0000092e: 01 DW_LNS_copy
+0x0000091a: 00 DW_LNE_set_address (0x000000000000058d)
+0x00000921: 05 DW_LNS_set_column (14)
+0x00000923: 06 DW_LNS_negate_stmt
+0x00000924: 01 DW_LNS_copy
             0x000000000000058d    122     14      1   0             0 
 
 
-0x0000092f: 00 DW_LNE_set_address (0x0000000000000596)
-0x00000936: 03 DW_LNS_advance_line (125)
-0x00000938: 05 DW_LNS_set_column (22)
-0x0000093a: 06 DW_LNS_negate_stmt
-0x0000093b: 01 DW_LNS_copy
+0x00000925: 00 DW_LNE_set_address (0x0000000000000596)
+0x0000092c: 03 DW_LNS_advance_line (125)
+0x0000092e: 05 DW_LNS_set_column (22)
+0x00000930: 06 DW_LNS_negate_stmt
+0x00000931: 01 DW_LNS_copy
             0x0000000000000596    125     22      1   0             0  is_stmt
 
 
-0x0000093c: 00 DW_LNE_set_address (0x00000000000005a3)
-0x00000943: 03 DW_LNS_advance_line (126)
-0x00000945: 05 DW_LNS_set_column (27)
-0x00000947: 01 DW_LNS_copy
+0x00000932: 00 DW_LNE_set_address (0x00000000000005a3)
+0x00000939: 03 DW_LNS_advance_line (126)
+0x0000093b: 05 DW_LNS_set_column (27)
+0x0000093d: 01 DW_LNS_copy
             0x00000000000005a3    126     27      1   0             0  is_stmt
 
 
-0x00000948: 00 DW_LNE_set_address (0x00000000000005ac)
-0x0000094f: 03 DW_LNS_advance_line (127)
-0x00000951: 05 DW_LNS_set_column (16)
-0x00000953: 01 DW_LNS_copy
+0x0000093e: 00 DW_LNE_set_address (0x00000000000005ac)
+0x00000945: 03 DW_LNS_advance_line (127)
+0x00000947: 05 DW_LNS_set_column (16)
+0x00000949: 01 DW_LNS_copy
             0x00000000000005ac    127     16      1   0             0  is_stmt
 
 
-0x00000954: 00 DW_LNE_set_address (0x00000000000005b4)
-0x0000095b: 05 DW_LNS_set_column (27)
-0x0000095d: 06 DW_LNS_negate_stmt
-0x0000095e: 01 DW_LNS_copy
+0x0000094a: 00 DW_LNE_set_address (0x00000000000005b4)
+0x00000951: 05 DW_LNS_set_column (27)
+0x00000953: 06 DW_LNS_negate_stmt
+0x00000954: 01 DW_LNS_copy
             0x00000000000005b4    127     27      1   0             0 
 
 
-0x0000095f: 00 DW_LNE_set_address (0x00000000000005b6)
-0x00000966: 05 DW_LNS_set_column (35)
-0x00000968: 01 DW_LNS_copy
+0x00000955: 00 DW_LNE_set_address (0x00000000000005b6)
+0x0000095c: 05 DW_LNS_set_column (35)
+0x0000095e: 01 DW_LNS_copy
             0x00000000000005b6    127     35      1   0             0 
 
 
-0x00000969: 00 DW_LNE_set_address (0x00000000000005bf)
-0x00000970: 05 DW_LNS_set_column (27)
-0x00000972: 01 DW_LNS_copy
+0x0000095f: 00 DW_LNE_set_address (0x00000000000005bf)
+0x00000966: 05 DW_LNS_set_column (27)
+0x00000968: 01 DW_LNS_copy
             0x00000000000005bf    127     27      1   0             0 
 
 
-0x00000973: 00 DW_LNE_set_address (0x00000000000005c4)
-0x0000097a: 05 DW_LNS_set_column (25)
-0x0000097c: 01 DW_LNS_copy
+0x00000969: 00 DW_LNE_set_address (0x00000000000005c4)
+0x00000970: 05 DW_LNS_set_column (25)
+0x00000972: 01 DW_LNS_copy
             0x00000000000005c4    127     25      1   0             0 
 
 
-0x0000097d: 00 DW_LNE_set_address (0x00000000000005c7)
-0x00000984: 03 DW_LNS_advance_line (126)
-0x00000986: 05 DW_LNS_set_column (27)
-0x00000988: 06 DW_LNS_negate_stmt
-0x00000989: 01 DW_LNS_copy
+0x00000973: 00 DW_LNE_set_address (0x00000000000005c7)
+0x0000097a: 03 DW_LNS_advance_line (126)
+0x0000097c: 05 DW_LNS_set_column (27)
+0x0000097e: 06 DW_LNS_negate_stmt
+0x0000097f: 01 DW_LNS_copy
             0x00000000000005c7    126     27      1   0             0  is_stmt
 
 
-0x0000098a: 00 DW_LNE_set_address (0x00000000000005cc)
-0x00000991: 05 DW_LNS_set_column (13)
-0x00000993: 06 DW_LNS_negate_stmt
-0x00000994: 01 DW_LNS_copy
+0x00000980: 00 DW_LNE_set_address (0x00000000000005cc)
+0x00000987: 05 DW_LNS_set_column (13)
+0x00000989: 06 DW_LNS_negate_stmt
+0x0000098a: 01 DW_LNS_copy
             0x00000000000005cc    126     13      1   0             0 
 
 
-0x00000995: 00 DW_LNE_set_address (0x00000000000005d4)
-0x0000099c: 03 DW_LNS_advance_line (128)
-0x0000099e: 06 DW_LNS_negate_stmt
-0x0000099f: 01 DW_LNS_copy
+0x0000098b: 00 DW_LNE_set_address (0x00000000000005d4)
+0x00000992: 03 DW_LNS_advance_line (128)
+0x00000994: 06 DW_LNS_negate_stmt
+0x00000995: 01 DW_LNS_copy
             0x00000000000005d4    128     13      1   0             0  is_stmt
 
 
-0x000009a0: 00 DW_LNE_set_address (0x00000000000005dc)
-0x000009a7: 05 DW_LNS_set_column (22)
-0x000009a9: 06 DW_LNS_negate_stmt
-0x000009aa: 01 DW_LNS_copy
+0x00000996: 00 DW_LNE_set_address (0x00000000000005dc)
+0x0000099d: 05 DW_LNS_set_column (22)
+0x0000099f: 06 DW_LNS_negate_stmt
+0x000009a0: 01 DW_LNS_copy
             0x00000000000005dc    128     22      1   0             0 
 
 
-0x000009ab: 00 DW_LNE_set_address (0x00000000000005e1)
-0x000009b2: 03 DW_LNS_advance_line (130)
-0x000009b4: 05 DW_LNS_set_column (16)
-0x000009b6: 06 DW_LNS_negate_stmt
-0x000009b7: 01 DW_LNS_copy
+0x000009a1: 00 DW_LNE_set_address (0x00000000000005e1)
+0x000009a8: 03 DW_LNS_advance_line (130)
+0x000009aa: 05 DW_LNS_set_column (16)
+0x000009ac: 06 DW_LNS_negate_stmt
+0x000009ad: 01 DW_LNS_copy
             0x00000000000005e1    130     16      1   0             0  is_stmt
 
 
-0x000009b8: 00 DW_LNE_set_address (0x00000000000005e9)
-0x000009bf: 05 DW_LNS_set_column (14)
-0x000009c1: 06 DW_LNS_negate_stmt
-0x000009c2: 01 DW_LNS_copy
+0x000009ae: 00 DW_LNE_set_address (0x00000000000005e9)
+0x000009b5: 05 DW_LNS_set_column (14)
+0x000009b7: 06 DW_LNS_negate_stmt
+0x000009b8: 01 DW_LNS_copy
             0x00000000000005e9    130     14      1   0             0 
 
 
-0x000009c3: 00 DW_LNE_set_address (0x00000000000005f8)
-0x000009ca: 05 DW_LNS_set_column (25)
-0x000009cc: 01 DW_LNS_copy
+0x000009b9: 00 DW_LNE_set_address (0x00000000000005f8)
+0x000009c0: 05 DW_LNS_set_column (25)
+0x000009c2: 01 DW_LNS_copy
             0x00000000000005f8    130     25      1   0             0 
 
 
-0x000009cd: 00 DW_LNE_set_address (0x00000000000005ff)
-0x000009d4: 03 DW_LNS_advance_line (133)
-0x000009d6: 05 DW_LNS_set_column (11)
-0x000009d8: 06 DW_LNS_negate_stmt
-0x000009d9: 01 DW_LNS_copy
+0x000009c3: 00 DW_LNE_set_address (0x00000000000005ff)
+0x000009ca: 03 DW_LNS_advance_line (133)
+0x000009cc: 05 DW_LNS_set_column (11)
+0x000009ce: 06 DW_LNS_negate_stmt
+0x000009cf: 01 DW_LNS_copy
             0x00000000000005ff    133     11      1   0             0  is_stmt
 
 
-0x000009da: 00 DW_LNE_set_address (0x0000000000000604)
-0x000009e1: 03 DW_LNS_advance_line (122)
-0x000009e3: 05 DW_LNS_set_column (16)
-0x000009e5: 01 DW_LNS_copy
+0x000009d0: 00 DW_LNE_set_address (0x0000000000000604)
+0x000009d7: 03 DW_LNS_advance_line (122)
+0x000009d9: 05 DW_LNS_set_column (16)
+0x000009db: 01 DW_LNS_copy
             0x0000000000000604    122     16      1   0             0  is_stmt
 
 
-0x000009e6: 00 DW_LNE_set_address (0x0000000000000609)
-0x000009ed: 05 DW_LNS_set_column (14)
-0x000009ef: 06 DW_LNS_negate_stmt
-0x000009f0: 01 DW_LNS_copy
+0x000009dc: 00 DW_LNE_set_address (0x0000000000000609)
+0x000009e3: 05 DW_LNS_set_column (14)
+0x000009e5: 06 DW_LNS_negate_stmt
+0x000009e6: 01 DW_LNS_copy
             0x0000000000000609    122     14      1   0             0 
 
 
-0x000009f1: 00 DW_LNE_set_address (0x000000000000060e)
-0x000009f8: 03 DW_LNS_advance_line (130)
-0x000009fa: 06 DW_LNS_negate_stmt
-0x000009fb: 01 DW_LNS_copy
-            0x000000000000060e    130     14      1   0             0  is_stmt
-
-
-0x000009fc: 00 DW_LNE_set_address (0x000000000000060f)
-0x00000a03: 03 DW_LNS_advance_line (110)
-0x00000a05: 05 DW_LNS_set_column (11)
-0x00000a07: 01 DW_LNS_copy
+0x000009e7: 00 DW_LNE_set_address (0x000000000000060f)
+0x000009ee: 03 DW_LNS_advance_line (110)
+0x000009f0: 05 DW_LNS_set_column (11)
+0x000009f2: 06 DW_LNS_negate_stmt
+0x000009f3: 01 DW_LNS_copy
             0x000000000000060f    110     11      1   0             0  is_stmt
 
 
-0x00000a08: 00 DW_LNE_set_address (0x0000000000000615)
-0x00000a0f: 03 DW_LNS_advance_line (138)
-0x00000a11: 05 DW_LNS_set_column (4)
-0x00000a13: 01 DW_LNS_copy
+0x000009f4: 00 DW_LNE_set_address (0x0000000000000615)
+0x000009fb: 03 DW_LNS_advance_line (138)
+0x000009fd: 05 DW_LNS_set_column (4)
+0x000009ff: 01 DW_LNS_copy
             0x0000000000000615    138      4      1   0             0  is_stmt
 
 
-0x00000a14: 00 DW_LNE_set_address (0x0000000000000619)
-0x00000a1b: 03 DW_LNS_advance_line (139)
-0x00000a1d: 01 DW_LNS_copy
+0x00000a00: 00 DW_LNE_set_address (0x0000000000000619)
+0x00000a07: 03 DW_LNS_advance_line (139)
+0x00000a09: 01 DW_LNS_copy
             0x0000000000000619    139      4      1   0             0  is_stmt
 
 
-0x00000a1e: 00 DW_LNE_set_address (0x0000000000000629)
-0x00000a25: 03 DW_LNS_advance_line (142)
-0x00000a27: 05 DW_LNS_set_column (20)
-0x00000a29: 01 DW_LNS_copy
+0x00000a0a: 00 DW_LNE_set_address (0x0000000000000629)
+0x00000a11: 03 DW_LNS_advance_line (142)
+0x00000a13: 05 DW_LNS_set_column (20)
+0x00000a15: 01 DW_LNS_copy
             0x0000000000000629    142     20      1   0             0  is_stmt
 
 
-0x00000a2a: 00 DW_LNE_set_address (0x0000000000000631)
-0x00000a31: 03 DW_LNS_advance_line (146)
-0x00000a33: 01 DW_LNS_copy
+0x00000a16: 00 DW_LNE_set_address (0x0000000000000631)
+0x00000a1d: 03 DW_LNS_advance_line (146)
+0x00000a1f: 01 DW_LNS_copy
             0x0000000000000631    146     20      1   0             0  is_stmt
 
 
-0x00000a34: 00 DW_LNE_set_address (0x0000000000000638)
-0x00000a3b: 03 DW_LNS_advance_line (147)
-0x00000a3d: 05 DW_LNS_set_column (7)
-0x00000a3f: 01 DW_LNS_copy
+0x00000a20: 00 DW_LNE_set_address (0x0000000000000638)
+0x00000a27: 03 DW_LNS_advance_line (147)
+0x00000a29: 05 DW_LNS_set_column (7)
+0x00000a2b: 01 DW_LNS_copy
             0x0000000000000638    147      7      1   0             0  is_stmt
 
 
-0x00000a40: 00 DW_LNE_set_address (0x000000000000063c)
-0x00000a47: 03 DW_LNS_advance_line (143)
-0x00000a49: 05 DW_LNS_set_column (11)
-0x00000a4b: 01 DW_LNS_copy
+0x00000a2c: 00 DW_LNE_set_address (0x000000000000063c)
+0x00000a33: 03 DW_LNS_advance_line (143)
+0x00000a35: 05 DW_LNS_set_column (11)
+0x00000a37: 01 DW_LNS_copy
             0x000000000000063c    143     11      1   0             0  is_stmt
 
 
-0x00000a4c: 00 DW_LNE_set_address (0x0000000000000640)
-0x00000a53: 05 DW_LNS_set_column (20)
-0x00000a55: 06 DW_LNS_negate_stmt
-0x00000a56: 01 DW_LNS_copy
+0x00000a38: 00 DW_LNE_set_address (0x0000000000000640)
+0x00000a3f: 05 DW_LNS_set_column (20)
+0x00000a41: 06 DW_LNS_negate_stmt
+0x00000a42: 01 DW_LNS_copy
             0x0000000000000640    143     20      1   0             0 
 
 
-0x00000a57: 00 DW_LNE_set_address (0x0000000000000645)
-0x00000a5e: 05 DW_LNS_set_column (11)
-0x00000a60: 01 DW_LNS_copy
+0x00000a43: 00 DW_LNE_set_address (0x0000000000000645)
+0x00000a4a: 05 DW_LNS_set_column (11)
+0x00000a4c: 01 DW_LNS_copy
             0x0000000000000645    143     11      1   0             0 
 
 
-0x00000a61: 00 DW_LNE_set_address (0x000000000000064c)
-0x00000a68: 03 DW_LNS_advance_line (141)
-0x00000a6a: 05 DW_LNS_set_column (4)
-0x00000a6c: 06 DW_LNS_negate_stmt
-0x00000a6d: 01 DW_LNS_copy
+0x00000a4d: 00 DW_LNE_set_address (0x000000000000064c)
+0x00000a54: 03 DW_LNS_advance_line (141)
+0x00000a56: 05 DW_LNS_set_column (4)
+0x00000a58: 06 DW_LNS_negate_stmt
+0x00000a59: 01 DW_LNS_copy
             0x000000000000064c    141      4      1   0             0  is_stmt
 
 
-0x00000a6e: 00 DW_LNE_set_address (0x0000000000000652)
-0x00000a75: 03 DW_LNS_advance_line (159)
-0x00000a77: 01 DW_LNS_copy
+0x00000a5a: 00 DW_LNE_set_address (0x0000000000000652)
+0x00000a61: 03 DW_LNS_advance_line (159)
+0x00000a63: 01 DW_LNS_copy
             0x0000000000000652    159      4      1   0             0  is_stmt
 
 
-0x00000a78: 00 DW_LNE_set_address (0x0000000000000669)
-0x00000a7f: 03 DW_LNS_advance_line (161)
-0x00000a81: 05 DW_LNS_set_column (1)
-0x00000a83: 01 DW_LNS_copy
+0x00000a64: 00 DW_LNE_set_address (0x0000000000000669)
+0x00000a6b: 03 DW_LNS_advance_line (161)
+0x00000a6d: 05 DW_LNS_set_column (1)
+0x00000a6f: 01 DW_LNS_copy
             0x0000000000000669    161      1      1   0             0  is_stmt
 
 
-0x00000a84: 00 DW_LNE_set_address (0x0000000000000673)
-0x00000a8b: 00 DW_LNE_end_sequence
+0x00000a70: 00 DW_LNE_set_address (0x0000000000000673)
+0x00000a77: 00 DW_LNE_end_sequence
             0x0000000000000673    161      1      1   0             0  is_stmt end_sequence
 
 
@@ -4716,7 +4704,7 @@
  (type $i32_=>_none (func (param i32)))
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 256 256))
- (data (i32.const 1024) "Pfannkuchen(%d) = %d.\n\00%d\00Wrong argument.")
+ (data (i32.const 1024) "Pfannkuchen(%d) = %d.\n\00%d\00Wrong argument.\00")
  (import "env" "malloc" (func $malloc (param i32) (result i32)))
  (import "env" "memcpy" (func $memcpy (param i32 i32 i32) (result i32)))
  (import "env" "free" (func $free (param i32)))
@@ -4862,11 +4850,11 @@
        ;; code offset: 0x7d
        (local.tee $4
         ;; code offset: 0x7c
-        (i32.add
+        (i32.sub
          ;; code offset: 0x78
          (local.get $2)
          ;; code offset: 0x7a
-         (i32.const -1)
+         (i32.const 1)
         )
        )
       )
@@ -4924,11 +4912,11 @@
             ;; code offset: 0xaa
             (local.tee $1
              ;; code offset: 0xa9
-             (i32.add
+             (i32.sub
               ;; code offset: 0xa5
               (local.get $2)
               ;; code offset: 0xa7
-              (i32.const -1)
+              (i32.const 1)
              )
             )
             ;; code offset: 0xac
@@ -5032,11 +5020,11 @@
            ;; code offset: 0x101
            (local.set $1
             ;; code offset: 0x100
-            (i32.add
+            (i32.sub
              ;; code offset: 0xfc
              (local.get $6)
              ;; code offset: 0xfe
-             (i32.const -1)
+             (i32.const 1)
             )
            )
            ;; code offset: 0x105
@@ -5114,11 +5102,11 @@
               ;; code offset: 0x13d
               (local.tee $1
                ;; code offset: 0x13c
-               (i32.add
+               (i32.sub
                 ;; code offset: 0x138
                 (local.get $1)
                 ;; code offset: 0x13a
-                (i32.const -1)
+                (i32.const 1)
                )
               )
              )
@@ -5313,7 +5301,7 @@
           )
          )
          ;; code offset: 0x1d5
-         (i32.add
+         (i32.sub
           ;; code offset: 0x1d1
           (local.tee $1
            ;; code offset: 0x1ce
@@ -5323,7 +5311,7 @@
            )
           )
           ;; code offset: 0x1d3
-          (i32.const -1)
+          (i32.const 1)
          )
         )
         ;; code offset: 0x1de
@@ -5391,11 +5379,11 @@
      ;; code offset: 0x20c
      (local.tee $4
       ;; code offset: 0x20b
-      (i32.add
+      (i32.sub
        ;; code offset: 0x207
        (local.get $2)
        ;; code offset: 0x209
-       (i32.const -1)
+       (i32.const 1)
       )
      )
     )
@@ -5444,11 +5432,11 @@
          ;; code offset: 0x233
          (local.tee $1
           ;; code offset: 0x232
-          (i32.add
+          (i32.sub
            ;; code offset: 0x22e
            (local.get $2)
            ;; code offset: 0x230
-           (i32.const -1)
+           (i32.const 1)
           )
          )
          ;; code offset: 0x235
@@ -5542,11 +5530,11 @@
         ;; code offset: 0x282
         (local.set $1
          ;; code offset: 0x281
-         (i32.add
+         (i32.sub
           ;; code offset: 0x27d
           (local.get $7)
           ;; code offset: 0x27f
-          (i32.const -1)
+          (i32.const 1)
          )
         )
         ;; code offset: 0x286
@@ -5624,11 +5612,11 @@
            ;; code offset: 0x2be
            (local.tee $1
             ;; code offset: 0x2bd
-            (i32.add
+            (i32.sub
              ;; code offset: 0x2b9
              (local.get $1)
              ;; code offset: 0x2bb
-             (i32.const -1)
+             (i32.const 1)
             )
            )
           )
@@ -5823,7 +5811,7 @@
        )
       )
       ;; code offset: 0x356
-      (i32.add
+      (i32.sub
        ;; code offset: 0x352
        (local.tee $1
         ;; code offset: 0x34f
@@ -5833,7 +5821,7 @@
         )
        )
        ;; code offset: 0x354
-       (i32.const -1)
+       (i32.const 1)
       )
      )
      ;; code offset: 0x35f
@@ -5977,11 +5965,11 @@
      ;; code offset: 0x3d7
      (local.set $2
       ;; code offset: 0x3d6
-      (i32.add
+      (i32.sub
        ;; code offset: 0x3d2
        (local.get $3)
        ;; code offset: 0x3d4
-       (i32.const -1)
+       (i32.const 1)
       )
      )
      ;; code offset: 0x3db
@@ -6255,11 +6243,11 @@
            ;; code offset: 0x4aa
            (local.tee $0
             ;; code offset: 0x4a9
-            (i32.add
+            (i32.sub
              ;; code offset: 0x4a5
              (local.get $2)
              ;; code offset: 0x4a7
-             (i32.const -1)
+             (i32.const 1)
             )
            )
            ;; code offset: 0x4ac
@@ -6304,11 +6292,11 @@
       ;; code offset: 0x4d2
       (local.set $6
        ;; code offset: 0x4d1
-       (i32.add
+       (i32.sub
         ;; code offset: 0x4cd
         (local.get $6)
         ;; code offset: 0x4cf
-        (i32.const -1)
+        (i32.const 1)
        )
       )
       ;; code offset: 0x4d4
@@ -6429,7 +6417,7 @@
          )
         )
         ;; code offset: 0x532
-        (i32.add
+        (i32.sub
          ;; code offset: 0x52e
          (local.tee $0
           ;; code offset: 0x52b
@@ -6439,7 +6427,7 @@
           )
          )
          ;; code offset: 0x530
-         (i32.const -1)
+         (i32.const 1)
         )
        )
        ;; code offset: 0x53b
@@ -6516,11 +6504,11 @@
           ;; code offset: 0x56c
           (local.tee $0
            ;; code offset: 0x56b
-           (i32.add
+           (i32.sub
             ;; code offset: 0x567
             (local.get $2)
             ;; code offset: 0x569
-            (i32.const -1)
+            (i32.const 1)
            )
           )
           ;; code offset: 0x56e
@@ -6565,11 +6553,11 @@
      ;; code offset: 0x594
      (local.set $6
       ;; code offset: 0x593
-      (i32.add
+      (i32.sub
        ;; code offset: 0x58f
        (local.get $6)
        ;; code offset: 0x591
-       (i32.const -1)
+       (i32.const 1)
       )
      )
      ;; code offset: 0x596
@@ -6690,7 +6678,7 @@
         )
        )
        ;; code offset: 0x5f4
-       (i32.add
+       (i32.sub
         ;; code offset: 0x5f0
         (local.tee $0
          ;; code offset: 0x5ed
@@ -6700,7 +6688,7 @@
          )
         )
         ;; code offset: 0x5f2
-        (i32.const -1)
+        (i32.const 1)
        )
       )
       ;; code offset: 0x5fd
@@ -6861,7 +6849,7 @@
  ;; custom section ".debug_loc", size 1073
  ;; custom section ".debug_ranges", size 88
  ;; custom section ".debug_abbrev", size 333
- ;; custom section ".debug_line", size 2702
+ ;; custom section ".debug_line", size 2682
  ;; custom section ".debug_str", size 434
  ;; custom section "producers", size 135
 )
diff --git a/binaryen/test/passes/fib2_dwarf.bin.txt b/binaryen/test/passes/fib2_dwarf.bin.txt
--- a/binaryen/test/passes/fib2_dwarf.bin.txt
+++ b/binaryen/test/passes/fib2_dwarf.bin.txt
@@ -618,7 +618,7 @@
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 256 256))
- (import "env" "__indirect_function_table" (table $timport$1 1 funcref))
+ (import "env" "__indirect_function_table" (table $timport$0 1 funcref))
  (global $global$0 (mut i32) (i32.const 5243904))
  (global $global$1 i32 (i32.const 1024))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
diff --git a/binaryen/test/passes/fib2_emptylocspan_dwarf.bin.txt b/binaryen/test/passes/fib2_emptylocspan_dwarf.bin.txt
--- a/binaryen/test/passes/fib2_emptylocspan_dwarf.bin.txt
+++ b/binaryen/test/passes/fib2_emptylocspan_dwarf.bin.txt
@@ -618,7 +618,7 @@
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 256 256))
- (import "env" "__indirect_function_table" (table $timport$1 1 funcref))
+ (import "env" "__indirect_function_table" (table $timport$0 1 funcref))
  (global $global$0 (mut i32) (i32.const 5243904))
  (global $global$1 i32 (i32.const 1024))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
diff --git a/binaryen/test/passes/fib_nonzero-low-pc_dwarf.bin.txt b/binaryen/test/passes/fib_nonzero-low-pc_dwarf.bin.txt
--- a/binaryen/test/passes/fib_nonzero-low-pc_dwarf.bin.txt
+++ b/binaryen/test/passes/fib_nonzero-low-pc_dwarf.bin.txt
@@ -365,7 +365,7 @@
 
 0x00000079:     DW_TAG_lexical_block [5] *
                   DW_AT_low_pc [DW_FORM_addr]	(0x000000000000001b)
-                  DW_AT_high_pc [DW_FORM_data4]	(0x00000000)
+                  DW_AT_high_pc [DW_FORM_data4]	(0x00000033)
 
 0x00000082:       DW_TAG_variable [4]  
                     DW_AT_location [DW_FORM_sec_offset]	(0x00000093: 
@@ -512,10 +512,10 @@
  (type $none_=>_none (func))
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (import "env" "memory" (memory $mimport$0 0))
- (import "env" "__indirect_function_table" (table $timport$1 0 funcref))
- (import "env" "__stack_pointer" (global $gimport$2 (mut i32)))
- (import "env" "__memory_base" (global $gimport$3 i32))
- (import "env" "__table_base" (global $gimport$4 i32))
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
+ (import "env" "__stack_pointer" (global $gimport$0 (mut i32)))
+ (import "env" "__memory_base" (global $gimport$1 i32))
+ (import "env" "__table_base" (global $gimport$2 i32))
  (global $global$0 i32 (i32.const 0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "__wasm_apply_relocs" (func $__wasm_apply_relocs))
diff --git a/binaryen/test/passes/flatten.bin.txt b/binaryen/test/passes/flatten.bin.txt
--- a/binaryen/test/passes/flatten.bin.txt
+++ b/binaryen/test/passes/flatten.bin.txt
@@ -7,8 +7,8 @@
  (type $none_=>_f32 (func (result f32)))
  (type $f32_=>_f32 (func (param f32) (result f32)))
  (type $none_=>_f64 (func (result f64)))
- (type $i64_f32_f64_i32_i32_=>_f64 (func (param i64 f32 f64 i32 i32) (result f64)))
  (type $f64_=>_f64 (func (param f64) (result f64)))
+ (type $i64_f32_f64_i32_i32_=>_f64 (func (param i64 f32 f64 i32 i32) (result f64)))
  (export "type-local-i32" (func $0))
  (export "type-local-i64" (func $1))
  (export "type-local-f32" (func $2))
diff --git a/binaryen/test/passes/flatten_dfo_O3_enable-threads.txt b/binaryen/test/passes/flatten_dfo_O3_enable-threads.txt
--- a/binaryen/test/passes/flatten_dfo_O3_enable-threads.txt
+++ b/binaryen/test/passes/flatten_dfo_O3_enable-threads.txt
@@ -2,8 +2,8 @@
  (type $none_=>_none (func))
  (type $none_=>_i32 (func (result i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
- (type $i64_i32_=>_f64 (func (param i64 i32) (result f64)))
  (type $f64_=>_f64 (func (param f64) (result f64)))
+ (type $i64_i32_=>_f64 (func (param i64 i32) (result f64)))
  (memory $0 (shared 1 1))
  (export "one" (func $0))
  (export "two" (func $1))
diff --git a/binaryen/test/passes/flatten_i64-to-i32-lowering.txt b/binaryen/test/passes/flatten_i64-to-i32-lowering.txt
--- a/binaryen/test/passes/flatten_i64-to-i32-lowering.txt
+++ b/binaryen/test/passes/flatten_i64-to-i32-lowering.txt
@@ -549,3 +549,24 @@
   )
  )
 )
+(module
+ (type $none_=>_none (func))
+ (table $0 37 funcref)
+ (global $i64toi32_i32$HIGH_BITS (mut i32) (i32.const 0))
+ (func $0
+  (unreachable)
+  (block
+   (unreachable)
+   (drop
+    (f64.const 1)
+   )
+   (drop
+    (i32.const -32768)
+   )
+   (drop
+    (i32.const 20)
+   )
+  )
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/flatten_i64-to-i32-lowering.wast b/binaryen/test/passes/flatten_i64-to-i32-lowering.wast
--- a/binaryen/test/passes/flatten_i64-to-i32-lowering.wast
+++ b/binaryen/test/passes/flatten_i64-to-i32-lowering.wast
@@ -63,4 +63,15 @@
   (global.set $f (i64.const 0x1122334455667788))
  )
 )
-
+(module
+ (type $i64_f64_i32_=>_none (func (param i64 f64 i32)))
+ (table $0 37 funcref)
+ (func $0
+  (call_indirect (type $i64_f64_i32_=>_none)
+   (unreachable)
+   (f64.const 1)
+   (i32.const -32768)
+   (i32.const 20)
+  )
+ )
+)
diff --git a/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.txt b/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.txt
--- a/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.txt
+++ b/binaryen/test/passes/flatten_simplify-locals-nonesting_dfo_O3.txt
@@ -1,8 +1,8 @@
 (module
  (type $none_=>_none (func))
  (type $i64_=>_none (func (param i64)))
- (type $i32_f64_f64_=>_i32 (func (param i32 f64 f64) (result i32)))
  (type $f64_=>_i32 (func (param f64) (result i32)))
+ (type $i32_f64_f64_=>_i32 (func (param i32 f64 f64) (result i32)))
  (type $none_=>_f64 (func (result f64)))
  (export "if-select" (func $0))
  (export "unreachable-body-update-zext" (func $1))
diff --git a/binaryen/test/passes/fpcast-emu.txt b/binaryen/test/passes/fpcast-emu.txt
--- a/binaryen/test/passes/fpcast-emu.txt
+++ b/binaryen/test/passes/fpcast-emu.txt
@@ -235,8 +235,8 @@
  )
 )
 (module
- (type $i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_=>_i64 (func (param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64) (result i64)))
  (type $f32_=>_i64 (func (param f32) (result i64)))
+ (type $i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_i64_=>_i64 (func (param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64) (result i64)))
  (table $0 42 42 funcref)
  (global $global$0 (mut i32) (i32.const 10))
  (export "func_106" (func $0))
diff --git a/binaryen/test/passes/fpcast-emu_pass-arg=max-func-params@5.txt b/binaryen/test/passes/fpcast-emu_pass-arg=max-func-params@5.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fpcast-emu_pass-arg=max-func-params@5.txt
@@ -0,0 +1,43 @@
+(module
+ (type $i64_i64_i64_i64_i64_=>_i64 (func (param i64 i64 i64 i64 i64) (result i64)))
+ (type $i32_i64_f32_f64_=>_none (func (param i32 i64 f32 f64)))
+ (table $0 10 10 funcref)
+ (elem (i32.const 0) $byn$fpcast-emu$a)
+ (func $a (param $x i32) (param $y i64) (param $z f32) (param $w f64)
+  (drop
+   (call_indirect (type $i64_i64_i64_i64_i64_=>_i64)
+    (i64.extend_i32_u
+     (i32.const 1)
+    )
+    (i64.const 2)
+    (i64.extend_i32_u
+     (i32.reinterpret_f32
+      (f32.const 3)
+     )
+    )
+    (i64.reinterpret_f64
+     (f64.const 4)
+    )
+    (i64.const 0)
+    (i32.const 1337)
+   )
+  )
+ )
+ (func $byn$fpcast-emu$a (param $0 i64) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (result i64)
+  (call $a
+   (i32.wrap_i64
+    (local.get $0)
+   )
+   (local.get $1)
+   (f32.reinterpret_i32
+    (i32.wrap_i64
+     (local.get $2)
+    )
+   )
+   (f64.reinterpret_i64
+    (local.get $3)
+   )
+  )
+  (i64.const 0)
+ )
+)
diff --git a/binaryen/test/passes/fpcast-emu_pass-arg=max-func-params@5.wast b/binaryen/test/passes/fpcast-emu_pass-arg=max-func-params@5.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/fpcast-emu_pass-arg=max-func-params@5.wast
@@ -0,0 +1,14 @@
+(module
+  (type $vijfd (func (param i32) (param i64) (param f32) (param f64)))
+  (table 10 10 funcref)
+  (elem (i32.const 0) $a)
+  (func $a (param $x i32) (param $y i64) (param $z f32) (param $w f64)
+    (call_indirect (type $vijfd)
+      (i32.const 1)
+      (i64.const 2)
+      (f32.const 3)
+      (f64.const 4)
+      (i32.const 1337)
+    )
+  )
+)
diff --git a/binaryen/test/passes/func-metrics.txt b/binaryen/test/passes/func-metrics.txt
--- a/binaryen/test/passes/func-metrics.txt
+++ b/binaryen/test/passes/func-metrics.txt
@@ -247,7 +247,7 @@
  [vars]         : 0       
  global.get     : 1       
 export: stackSave (0)
- [removable-bytes-without-it]: 70      
+ [removable-bytes-without-it]: 56      
  [total]        : 0       
 (module
  (type $none_=>_i32 (func (result i32)))
diff --git a/binaryen/test/passes/fuzz-exec_O.txt b/binaryen/test/passes/fuzz-exec_O.txt
--- a/binaryen/test/passes/fuzz-exec_O.txt
+++ b/binaryen/test/passes/fuzz-exec_O.txt
@@ -31,59 +31,56 @@
 [fuzz-exec] comparing func_0
 [fuzz-exec] comparing func_1
 [fuzz-exec] calling div
-[fuzz-exec] note result: div => -nan:0x63017a
+[fuzz-exec] note result: div => nan:0x400000
 [fuzz-exec] calling mul1
-[fuzz-exec] note result: mul1 => -nan:0x74546d
+[fuzz-exec] note result: mul1 => nan:0x400000
 [fuzz-exec] calling mul2
-[fuzz-exec] note result: mul2 => -nan:0x74546d
+[fuzz-exec] note result: mul2 => nan:0x400000
 [fuzz-exec] calling add1
-[fuzz-exec] note result: add1 => -nan:0x74546d
+[fuzz-exec] note result: add1 => nan:0x400000
 [fuzz-exec] calling add2
-[fuzz-exec] note result: add2 => -nan:0x74546d
+[fuzz-exec] note result: add2 => nan:0x400000
 [fuzz-exec] calling add3
-[fuzz-exec] note result: add3 => -nan:0x74546d
+[fuzz-exec] note result: add3 => nan:0x400000
 [fuzz-exec] calling add4
-[fuzz-exec] note result: add4 => -nan:0x74546d
+[fuzz-exec] note result: add4 => nan:0x400000
 [fuzz-exec] calling sub1
-[fuzz-exec] note result: sub1 => -nan:0x74546d
+[fuzz-exec] note result: sub1 => nan:0x400000
 [fuzz-exec] calling sub2
-[fuzz-exec] note result: sub2 => -nan:0x74546d
+[fuzz-exec] note result: sub2 => nan:0x400000
 (module
  (type $none_=>_f32 (func (result f32)))
  (export "div" (func $0))
- (export "mul1" (func $1))
- (export "mul2" (func $1))
- (export "add1" (func $1))
- (export "add2" (func $1))
- (export "add3" (func $1))
- (export "add4" (func $1))
- (export "sub1" (func $1))
- (export "sub2" (func $1))
+ (export "mul1" (func $0))
+ (export "mul2" (func $0))
+ (export "add1" (func $0))
+ (export "add2" (func $0))
+ (export "add3" (func $0))
+ (export "add4" (func $0))
+ (export "sub1" (func $0))
+ (export "sub2" (func $0))
  (func $0 (; has Stack IR ;) (result f32)
-  (f32.const -nan:0x63017a)
- )
- (func $1 (; has Stack IR ;) (result f32)
-  (f32.const -nan:0x74546d)
+  (f32.const nan:0x400000)
  )
 )
 [fuzz-exec] calling div
-[fuzz-exec] note result: div => -nan:0x63017a
+[fuzz-exec] note result: div => nan:0x400000
 [fuzz-exec] calling mul1
-[fuzz-exec] note result: mul1 => -nan:0x74546d
+[fuzz-exec] note result: mul1 => nan:0x400000
 [fuzz-exec] calling mul2
-[fuzz-exec] note result: mul2 => -nan:0x74546d
+[fuzz-exec] note result: mul2 => nan:0x400000
 [fuzz-exec] calling add1
-[fuzz-exec] note result: add1 => -nan:0x74546d
+[fuzz-exec] note result: add1 => nan:0x400000
 [fuzz-exec] calling add2
-[fuzz-exec] note result: add2 => -nan:0x74546d
+[fuzz-exec] note result: add2 => nan:0x400000
 [fuzz-exec] calling add3
-[fuzz-exec] note result: add3 => -nan:0x74546d
+[fuzz-exec] note result: add3 => nan:0x400000
 [fuzz-exec] calling add4
-[fuzz-exec] note result: add4 => -nan:0x74546d
+[fuzz-exec] note result: add4 => nan:0x400000
 [fuzz-exec] calling sub1
-[fuzz-exec] note result: sub1 => -nan:0x74546d
+[fuzz-exec] note result: sub1 => nan:0x400000
 [fuzz-exec] calling sub2
-[fuzz-exec] note result: sub2 => -nan:0x74546d
+[fuzz-exec] note result: sub2 => nan:0x400000
 [fuzz-exec] comparing add1
 [fuzz-exec] comparing add2
 [fuzz-exec] comparing add3
diff --git a/binaryen/test/passes/fuzz-exec_all-features.txt b/binaryen/test/passes/fuzz-exec_all-features.txt
--- a/binaryen/test/passes/fuzz-exec_all-features.txt
+++ b/binaryen/test/passes/fuzz-exec_all-features.txt
@@ -98,7 +98,7 @@
   )
  )
  (func $3 (result i32)
-  (atomic.notify
+  (memory.atomic.notify
    (i32.const 1)
    (i32.const 1)
   )
@@ -119,7 +119,7 @@
  )
  (func $5
   (drop
-   (atomic.notify offset=22
+   (memory.atomic.notify offset=22
     (i32.const -104)
     (i32.const -72)
    )
@@ -207,3 +207,15 @@
 )
 [fuzz-exec] calling rmw-reads-modifies-and-writes-asymmetrical
 [LoggingExternalInterface logging 214]
+[fuzz-exec] calling func
+[fuzz-exec] note result: func => funcref(func)
+(module
+ (type $none_=>_funcref (func (result funcref)))
+ (export "func" (func $func))
+ (func $func (result funcref)
+  (ref.func $func)
+ )
+)
+[fuzz-exec] calling func
+[fuzz-exec] note result: func => funcref(func)
+[fuzz-exec] comparing func
diff --git a/binaryen/test/passes/fuzz-exec_all-features.wast b/binaryen/test/passes/fuzz-exec_all-features.wast
--- a/binaryen/test/passes/fuzz-exec_all-features.wast
+++ b/binaryen/test/passes/fuzz-exec_all-features.wast
@@ -51,7 +51,7 @@
   )
  )
  (func "unaligned_notify" (result i32)
-  (atomic.notify
+  (memory.atomic.notify
    (i32.const 1) ;; unaligned
    (i32.const 1)
   )
@@ -70,7 +70,7 @@
  )
  (func "oob_notify"
   (drop
-   (atomic.notify offset=22
+   (memory.atomic.notify offset=22
     (i32.const -104) ;; illegal address
     (i32.const -72)
    )
@@ -119,5 +119,11 @@
     (i32.const 3)
    )
   )
+ )
+)
+(module
+ (export "func" (func $func))
+ (func $func (result funcref)
+  (ref.func $func)
  )
 )
diff --git a/binaryen/test/passes/fuzz_metrics_noprint.bin.txt b/binaryen/test/passes/fuzz_metrics_noprint.bin.txt
--- a/binaryen/test/passes/fuzz_metrics_noprint.bin.txt
+++ b/binaryen/test/passes/fuzz_metrics_noprint.bin.txt
@@ -1,30 +1,30 @@
 total
  [events]       : 0       
- [exports]      : 18      
- [funcs]        : 22      
+ [exports]      : 51      
+ [funcs]        : 67      
  [globals]      : 7       
  [imports]      : 4       
  [memory-data]  : 4       
- [table-data]   : 9       
- [total]        : 4993    
- [vars]         : 58      
- binary         : 397     
- block          : 736     
- break          : 204     
- call           : 173     
- call_indirect  : 32      
- const          : 823     
- drop           : 42      
- global.get     : 421     
- global.set     : 190     
- if             : 292     
- load           : 95      
- local.get      : 392     
- local.set      : 297     
- loop           : 146     
- nop            : 97      
- return         : 189     
- select         : 39      
- store          : 55      
- switch         : 1       
- unary          : 372     
+ [table-data]   : 18      
+ [total]        : 4870    
+ [vars]         : 236     
+ binary         : 368     
+ block          : 699     
+ break          : 191     
+ call           : 300     
+ call_indirect  : 39      
+ const          : 847     
+ drop           : 91      
+ global.get     : 403     
+ global.set     : 171     
+ if             : 260     
+ load           : 85      
+ local.get      : 374     
+ local.set      : 251     
+ loop           : 111     
+ nop            : 86      
+ return         : 187     
+ select         : 30      
+ store          : 36      
+ unary          : 340     
+ unreachable    : 1       
diff --git a/binaryen/test/passes/ignore_missing_func_dwarf.bin.txt b/binaryen/test/passes/ignore_missing_func_dwarf.bin.txt
--- a/binaryen/test/passes/ignore_missing_func_dwarf.bin.txt
+++ b/binaryen/test/passes/ignore_missing_func_dwarf.bin.txt
@@ -6,7 +6,7 @@
  (import "env" "memory" (memory $mimport$0 256 256))
  (data (i32.const 1024) "\nvoid used(int x) {\n  x++;\n  x--;\n  return x;\n}\n\nvoid unused(int x) {\n  x >>= 1;\n  x <<= 1;\n  return x;\n}\n\nint main() {\n  return used(42);\n}\n\00")
  (data (i32.const 1168) "\00\04\00\00")
- (import "env" "__indirect_function_table" (table $timport$1 1 funcref))
+ (import "env" "__indirect_function_table" (table $timport$0 1 funcref))
  (global $global$0 (mut i32) (i32.const 5244064))
  (global $global$1 i32 (i32.const 1172))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
@@ -829,7 +829,7 @@
  (import "env" "memory" (memory $mimport$0 256 256))
  (data (i32.const 1024) "\nvoid used(int x) {\n  x++;\n  x--;\n  return x;\n}\n\nvoid unused(int x) {\n  x >>= 1;\n  x <<= 1;\n  return x;\n}\n\nint main() {\n  return used(42);\n}\n\00")
  (data (i32.const 1168) "\00\04\00\00")
- (import "env" "__indirect_function_table" (table $timport$1 1 funcref))
+ (import "env" "__indirect_function_table" (table $timport$0 1 funcref))
  (global $global$0 (mut i32) (i32.const 5244064))
  (global $global$1 i32 (i32.const 1172))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
diff --git a/binaryen/test/passes/inlining-optimizing_optimize-level=3.txt b/binaryen/test/passes/inlining-optimizing_optimize-level=3.txt
--- a/binaryen/test/passes/inlining-optimizing_optimize-level=3.txt
+++ b/binaryen/test/passes/inlining-optimizing_optimize-level=3.txt
@@ -2467,7 +2467,7 @@
        (if (result i32)
         (i32.lt_u
          (local.tee $8
-          (i32.add
+          (i32.sub
            (local.tee $12
             (i32.load8_s
              (local.tee $10
@@ -2478,7 +2478,7 @@
              )
             )
            )
-           (i32.const -48)
+           (i32.const 48)
           )
          )
          (i32.const 10)
@@ -2562,9 +2562,9 @@
             (i32.and
              (i32.shl
               (i32.const 1)
-              (i32.add
+              (i32.sub
                (local.get $6)
-               (i32.const -32)
+               (i32.const 32)
               )
              )
              (i32.const 75913)
@@ -2583,7 +2583,7 @@
            (i32.or
             (i32.shl
              (i32.const 1)
-             (i32.add
+             (i32.sub
               (i32.shr_s
                (i32.shl
                 (local.get $1)
@@ -2591,7 +2591,7 @@
                )
                (i32.const 24)
               )
-              (i32.const -32)
+              (i32.const 32)
              )
             )
             (local.get $12)
@@ -2642,7 +2642,7 @@
             (br_if $__rjti$0
              (i32.ge_u
               (local.tee $12
-               (i32.add
+               (i32.sub
                 (i32.load8_s
                  (local.tee $6
                   (i32.add
@@ -2651,7 +2651,7 @@
                   )
                  )
                 )
-                (i32.const -48)
+                (i32.const 48)
                )
               )
               (i32.const 10)
@@ -2681,11 +2681,11 @@
                (i32.add
                 (local.get $3)
                 (i32.shl
-                 (i32.add
+                 (i32.sub
                   (i32.load8_s
                    (local.get $6)
                   )
-                  (i32.const -48)
+                  (i32.const 48)
                  )
                  (i32.const 3)
                 )
@@ -2790,7 +2790,7 @@
         (if (result i32)
          (i32.lt_u
           (local.tee $6
-           (i32.add
+           (i32.sub
             (i32.shr_s
              (i32.shl
               (local.get $6)
@@ -2798,7 +2798,7 @@
              )
              (i32.const 24)
             )
-            (i32.const -48)
+            (i32.const 48)
            )
           )
           (i32.const 10)
@@ -2820,7 +2820,7 @@
            (if
             (i32.lt_u
              (local.tee $9
-              (i32.add
+              (i32.sub
                (i32.load8_s
                 (local.tee $10
                  (i32.add
@@ -2829,7 +2829,7 @@
                  )
                 )
                )
-               (i32.const -48)
+               (i32.const 48)
               )
              )
              (i32.const 10)
@@ -2907,9 +2907,9 @@
             (if (result i32)
              (i32.lt_u
               (local.tee $9
-               (i32.add
+               (i32.sub
                 (local.get $8)
-                (i32.const -48)
+                (i32.const 48)
                )
               )
               (i32.const 10)
@@ -2947,7 +2947,7 @@
               )
               (i32.ge_u
                (local.tee $6
-                (i32.add
+                (i32.sub
                  (i32.load8_s
                   (local.tee $10
                    (i32.add
@@ -2956,7 +2956,7 @@
                    )
                   )
                  )
-                 (i32.const -48)
+                 (i32.const 48)
                 )
                )
                (i32.const 10)
@@ -2970,7 +2970,7 @@
          (if
           (i32.lt_u
            (local.tee $8
-            (i32.add
+            (i32.sub
              (i32.load8_s
               (local.tee $6
                (i32.add
@@ -2979,7 +2979,7 @@
                )
               )
              )
-             (i32.const -48)
+             (i32.const 48)
             )
            )
            (i32.const 10)
@@ -3008,11 +3008,11 @@
                (i32.add
                 (local.get $3)
                 (i32.shl
-                 (i32.add
+                 (i32.sub
                   (i32.load8_s
                    (local.get $6)
                   )
-                  (i32.const -48)
+                  (i32.const 48)
                  )
                  (i32.const 3)
                 )
@@ -3095,11 +3095,11 @@
         (if
          (i32.gt_u
           (local.tee $11
-           (i32.add
+           (i32.sub
             (i32.load8_s
              (local.get $8)
             )
-            (i32.const -65)
+            (i32.const 65)
            )
           )
           (i32.const 57)
@@ -3119,7 +3119,7 @@
         )
         (if (result i32)
          (i32.lt_u
-          (i32.add
+          (i32.sub
            (local.tee $11
             (i32.and
              (local.tee $15
@@ -3139,7 +3139,7 @@
              (i32.const 255)
             )
            )
-           (i32.const -1)
+           (i32.const 1)
           )
           (i32.const 8)
          )
@@ -3548,9 +3548,9 @@
                                    (loop $while-in32
                                     (i32.store8
                                      (local.tee $8
-                                      (i32.add
+                                      (i32.sub
                                        (local.get $8)
-                                       (i32.const -1)
+                                       (i32.const 1)
                                       )
                                      )
                                      (i32.or
@@ -3602,9 +3602,9 @@
                                       )
                                      )
                                      (local.get $6)
-                                     (i32.lt_s
-                                      (local.get $6)
+                                     (i32.gt_s
                                       (local.get $5)
+                                      (local.get $6)
                                      )
                                     )
                                    )
@@ -3645,7 +3645,7 @@
                                      (i32.const 0)
                                      (local.get $7)
                                     )
-                                    (i32.gt_u
+                                    (i32.ne
                                      (local.get $5)
                                      (i32.const 0)
                                     )
@@ -3926,11 +3926,11 @@
                              )
                              (i32.store
                               (local.get $21)
-                              (i32.add
+                              (i32.sub
                                (i32.load
                                 (local.get $21)
                                )
-                               (i32.const -1)
+                               (i32.const 1)
                               )
                              )
                             )
@@ -3990,20 +3990,14 @@
                                   )
                                   (br_if $while-in54
                                    (local.tee $5
-                                    (i32.add
+                                    (i32.sub
                                      (local.get $5)
-                                     (i32.const -1)
+                                     (i32.const 1)
                                     )
                                    )
                                   )
                                  )
-                                 (if (result f64)
-                                  (i32.eq
-                                   (i32.load8_s
-                                    (local.get $9)
-                                   )
-                                   (i32.const 45)
-                                  )
+                                 (select
                                   (f64.neg
                                    (f64.add
                                     (local.get $14)
@@ -4022,6 +4016,12 @@
                                    )
                                    (local.get $14)
                                   )
+                                  (i32.eq
+                                   (i32.load8_s
+                                    (local.get $9)
+                                   )
+                                   (i32.const 45)
+                                  )
                                  )
                                 )
                                )
@@ -4079,9 +4079,9 @@
                                )
                               )
                               (i32.store8
-                               (i32.add
+                               (i32.sub
                                 (local.get $5)
-                                (i32.const -1)
+                                (i32.const 1)
                                )
                                (i32.add
                                 (i32.and
@@ -4096,9 +4096,9 @@
                               )
                               (i32.store8
                                (local.tee $8
-                                (i32.add
+                                (i32.sub
                                  (local.get $5)
-                                 (i32.const -2)
+                                 (i32.const 2)
                                 )
                                )
                                (i32.add
@@ -4375,11 +4375,11 @@
                                (i32.store
                                 (local.get $21)
                                 (local.tee $5
-                                 (i32.add
+                                 (i32.sub
                                   (i32.load
                                    (local.get $21)
                                   )
-                                  (i32.const -28)
+                                  (i32.const 28)
                                  )
                                 )
                                )
@@ -4490,9 +4490,9 @@
                                (if
                                 (i32.ge_u
                                  (local.tee $9
-                                  (i32.add
+                                  (i32.sub
                                    (local.get $7)
-                                   (i32.const -4)
+                                   (i32.const 4)
                                   )
                                  )
                                  (local.get $5)
@@ -4508,22 +4508,22 @@
                                     (block (result i32)
                                      (global.set $tempRet0
                                       (i32.add
-                                       (i32.lt_u
+                                       (i32.gt_u
+                                        (local.tee $20
+                                         (call $_bitshift64Shl
+                                          (i32.load
+                                           (local.get $9)
+                                          )
+                                          (i32.const 0)
+                                          (local.get $15)
+                                         )
+                                        )
                                         (local.tee $11
                                          (i32.add
                                           (local.get $11)
-                                          (local.tee $20
-                                           (call $_bitshift64Shl
-                                            (i32.load
-                                             (local.get $9)
-                                            )
-                                            (i32.const 0)
-                                            (local.get $15)
-                                           )
-                                          )
+                                          (local.get $20)
                                          )
                                         )
-                                        (local.get $20)
                                        )
                                        (global.get $tempRet0)
                                       )
@@ -4548,9 +4548,9 @@
                                   (br_if $while-in66
                                    (i32.ge_u
                                     (local.tee $9
-                                     (i32.add
+                                     (i32.sub
                                       (local.get $9)
-                                      (i32.const -4)
+                                      (i32.const 4)
                                      )
                                     )
                                     (local.get $5)
@@ -4564,9 +4564,9 @@
                                  )
                                  (i32.store
                                   (local.tee $5
-                                   (i32.add
+                                   (i32.sub
                                     (local.get $5)
-                                    (i32.const -4)
+                                    (i32.const 4)
                                    )
                                   )
                                   (local.get $11)
@@ -4575,17 +4575,17 @@
                                )
                                (loop $while-in68
                                 (if
-                                 (i32.gt_u
-                                  (local.get $7)
+                                 (i32.lt_u
                                   (local.get $5)
+                                  (local.get $7)
                                  )
                                  (if
                                   (i32.eqz
                                    (i32.load
                                     (local.tee $9
-                                     (i32.add
+                                     (i32.sub
                                       (local.get $7)
-                                      (i32.const -4)
+                                      (i32.const 4)
                                      )
                                     )
                                    )
@@ -4680,18 +4680,18 @@
                                  )
                                 )
                                 (if
-                                 (i32.lt_u
-                                  (local.get $6)
+                                 (i32.gt_u
                                   (local.get $5)
+                                  (local.get $6)
                                  )
                                  (block $do-once71
                                   (local.set $11
-                                   (i32.add
+                                   (i32.sub
                                     (i32.shl
                                      (i32.const 1)
                                      (local.get $15)
                                     )
-                                    (i32.const -1)
+                                    (i32.const 1)
                                    )
                                   )
                                   (local.set $35
@@ -4946,7 +4946,7 @@
                                  )
                                 )
                                )
-                               (i32.add
+                               (i32.sub
                                 (i32.mul
                                  (i32.shr_s
                                   (i32.sub
@@ -4957,7 +4957,7 @@
                                  )
                                  (i32.const 9)
                                 )
-                                (i32.const -9)
+                                (i32.const 9)
                                )
                               )
                               (block (result i32)
@@ -5017,7 +5017,7 @@
                                 (local.tee $8
                                  (i32.load
                                   (local.tee $6
-                                   (i32.add
+                                   (i32.sub
                                     (i32.add
                                      (local.get $20)
                                      (i32.shl
@@ -5025,7 +5025,7 @@
                                       (i32.const 2)
                                      )
                                     )
-                                    (i32.const -4092)
+                                    (i32.const 4092)
                                    )
                                   )
                                  )
@@ -5167,18 +5167,18 @@
                                    (if
                                     (i32.lt_u
                                      (local.tee $6
-                                      (i32.add
+                                      (i32.sub
                                        (local.get $6)
-                                       (i32.const -4)
+                                       (i32.const 4)
                                       )
                                      )
                                      (local.get $5)
                                     )
                                     (i32.store
                                      (local.tee $5
-                                      (i32.add
+                                      (i32.sub
                                        (local.get $5)
-                                       (i32.const -4)
+                                       (i32.const 4)
                                       )
                                      )
                                      (i32.const 0)
@@ -5263,9 +5263,9 @@
                                  )
                                 )
                                 (local.get $9)
-                                (i32.gt_u
-                                 (local.get $9)
+                                (i32.lt_u
                                  (local.get $5)
+                                 (local.get $9)
                                 )
                                )
                               )
@@ -5306,9 +5306,9 @@
                                (if (result i32)
                                 (i32.load
                                  (local.tee $7
-                                  (i32.add
+                                  (i32.sub
                                    (local.get $5)
-                                   (i32.const -4)
+                                   (i32.const 4)
                                   )
                                  )
                                 )
@@ -5363,28 +5363,28 @@
                                       (block (result i32)
                                        (local.set $19
                                         (i32.sub
-                                         (i32.add
+                                         (i32.sub
                                           (local.get $5)
-                                          (i32.const -1)
+                                          (i32.const 1)
                                          )
                                          (local.get $8)
                                         )
                                        )
-                                       (i32.add
+                                       (i32.sub
                                         (local.get $16)
-                                        (i32.const -1)
+                                        (i32.const 1)
                                        )
                                       )
                                       (block (result i32)
                                        (local.set $19
-                                        (i32.add
+                                        (i32.sub
                                          (local.get $5)
-                                         (i32.const -1)
+                                         (i32.const 1)
                                         )
                                        )
-                                       (i32.add
+                                       (i32.sub
                                         (local.get $16)
-                                        (i32.const -2)
+                                        (i32.const 2)
                                        )
                                       )
                                      )
@@ -5407,9 +5407,9 @@
                                        (i32.eqz
                                         (local.tee $16
                                          (i32.load
-                                          (i32.add
+                                          (i32.sub
                                            (local.get $9)
-                                           (i32.const -4)
+                                           (i32.const 4)
                                           )
                                          )
                                         )
@@ -5474,7 +5474,7 @@
                                      )
                                     )
                                     (local.set $6
-                                     (i32.add
+                                     (i32.sub
                                       (i32.mul
                                        (i32.shr_s
                                         (i32.sub
@@ -5485,7 +5485,7 @@
                                        )
                                        (i32.const 9)
                                       )
-                                      (i32.const -9)
+                                      (i32.const 9)
                                      )
                                     )
                                     (if (result i32)
@@ -5517,9 +5517,9 @@
                                          )
                                         )
                                        )
-                                       (i32.lt_s
-                                        (local.get $19)
+                                       (i32.gt_s
                                         (local.get $5)
+                                        (local.get $19)
                                        )
                                       )
                                      )
@@ -5547,9 +5547,9 @@
                                          )
                                         )
                                        )
-                                       (i32.lt_s
-                                        (local.get $19)
+                                       (i32.gt_s
                                         (local.get $5)
+                                        (local.get $19)
                                        )
                                       )
                                      )
@@ -5643,9 +5643,9 @@
                                   (loop $while-in98
                                    (i32.store8
                                     (local.tee $6
-                                     (i32.add
+                                     (i32.sub
                                       (local.get $6)
-                                      (i32.const -1)
+                                      (i32.const 1)
                                      )
                                     )
                                     (i32.const 48)
@@ -5662,9 +5662,9 @@
                                   )
                                  )
                                  (i32.store8
-                                  (i32.add
+                                  (i32.sub
                                    (local.get $6)
-                                   (i32.const -1)
+                                   (i32.const 1)
                                   )
                                   (i32.add
                                    (i32.and
@@ -5679,9 +5679,9 @@
                                  )
                                  (i32.store8
                                   (local.tee $16
-                                   (i32.add
+                                   (i32.sub
                                     (local.get $6)
-                                    (i32.const -2)
+                                    (i32.const 2)
                                    )
                                   )
                                   (local.get $7)
@@ -5779,9 +5779,9 @@
                                   (loop $while-in106
                                    (i32.store8
                                     (local.tee $7
-                                     (i32.add
+                                     (i32.sub
                                       (local.get $7)
-                                      (i32.const -1)
+                                      (i32.const 1)
                                      )
                                     )
                                     (i32.const 48)
@@ -5886,9 +5886,9 @@
                                    (loop $while-in112
                                     (i32.store8
                                      (local.tee $6
-                                      (i32.add
+                                      (i32.sub
                                        (local.get $6)
-                                       (i32.const -1)
+                                       (i32.const 1)
                                       )
                                      )
                                      (i32.const 48)
@@ -5926,9 +5926,9 @@
                                    )
                                   )
                                   (local.set $6
-                                   (i32.add
+                                   (i32.sub
                                     (local.get $5)
-                                    (i32.const -9)
+                                    (i32.const 9)
                                    )
                                   )
                                   (if (result i32)
@@ -6085,9 +6085,9 @@
                                       (loop $while-in118
                                        (i32.store8
                                         (local.tee $5
-                                         (i32.add
+                                         (i32.sub
                                           (local.get $5)
-                                          (i32.const -1)
+                                          (i32.const 1)
                                          )
                                         )
                                         (i32.const 48)
@@ -6359,9 +6359,9 @@
                           (loop $while-in123 (result i32)
                            (i32.store8
                             (local.tee $8
-                             (i32.add
+                             (i32.sub
                               (local.get $8)
-                              (i32.const -1)
+                              (i32.const 1)
                              )
                             )
                             (i32.or
@@ -6651,9 +6651,9 @@
                         )
                        )
                        (br_if $while-in127
-                        (i32.lt_u
-                         (local.get $6)
+                        (i32.gt_u
                          (local.get $5)
+                         (local.get $6)
                         )
                        )
                        (local.get $5)
@@ -6675,9 +6675,9 @@
                   (select
                    (local.get $17)
                    (local.get $7)
-                   (i32.gt_s
-                    (local.get $17)
+                   (i32.lt_s
                     (local.get $7)
+                    (local.get $17)
                    )
                   )
                  )
@@ -6733,9 +6733,9 @@
                      )
                     )
                    )
-                   (i32.gt_s
-                    (local.get $6)
+                   (i32.lt_s
                     (local.get $5)
+                    (local.get $6)
                    )
                   )
                   (block (result i32)
@@ -6762,9 +6762,9 @@
           )
          )
          (local.get $17)
-         (i32.lt_s
-          (local.get $17)
+         (i32.gt_s
           (local.get $5)
+          (local.get $17)
          )
         )
        )
@@ -7349,16 +7349,13 @@
  (func $_fmt_u (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
   (local $3 i32)
   (if
-   (i32.gt_u
-    (local.get $1)
-    (i32.const 0)
-   )
+   (local.get $1)
    (loop $while-in
     (i32.store8
      (local.tee $2
-      (i32.add
+      (i32.sub
        (local.get $2)
-       (i32.const -1)
+       (i32.const 1)
       )
      )
      (i32.or
@@ -7401,9 +7398,9 @@
    (loop $while-in1
     (i32.store8
      (local.tee $2
-      (i32.add
+      (i32.sub
        (local.get $2)
-       (i32.const -1)
+       (i32.const 1)
       )
      )
      (i32.or
@@ -7414,18 +7411,22 @@
       (i32.const 48)
      )
     )
-    (local.set $0
+    (local.set $1
      (i32.div_u
-      (local.tee $1
-       (local.get $0)
-      )
+      (local.get $0)
       (i32.const 10)
      )
     )
-    (br_if $while-in1
+    (if
      (i32.ge_u
-      (local.get $1)
+      (local.get $0)
       (i32.const 10)
+     )
+     (block
+      (local.set $0
+       (local.get $1)
+      )
+      (br $while-in1)
      )
     )
    )
diff --git a/binaryen/test/passes/inlining_all-features.txt b/binaryen/test/passes/inlining_all-features.txt
--- a/binaryen/test/passes/inlining_all-features.txt
+++ b/binaryen/test/passes/inlining_all-features.txt
@@ -47,3 +47,42 @@
   )
  )
 )
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (global $global$0 (mut funcref) (ref.func $0))
+ (func $0 (result i32)
+  (i32.const 1337)
+ )
+ (func $1 (result i32)
+  (block $__inlined_func$0 (result i32)
+   (i32.const 1337)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (start $0)
+ (func $0
+  (nop)
+ )
+ (func $1
+  (block $__inlined_func$0
+   (nop)
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (export "func_36_invoker" (func $1))
+ (func $1
+  (block $__inlined_func$0
+   (block
+    (call_ref
+     (ref.null $none_=>_none)
+    )
+    (br $__inlined_func$0)
+   )
+   (br $__inlined_func$0)
+  )
+ )
+)
diff --git a/binaryen/test/passes/inlining_all-features.wast b/binaryen/test/passes/inlining_all-features.wast
--- a/binaryen/test/passes/inlining_all-features.wast
+++ b/binaryen/test/passes/inlining_all-features.wast
@@ -36,3 +36,38 @@
     )
   )
 )
+(module
+ ;; a function reference in a global's init should be noticed, and prevent us
+ ;; from removing an inlined function
+ (global $global$0 (mut funcref) (ref.func $0))
+ (func $0 (result i32)
+  (i32.const 1337)
+ )
+ (func $1 (result i32)
+  (call $0)
+ )
+)
+(module
+ ;; a function reference in the start should be noticed, and prevent us
+ ;; from removing an inlined function
+ (start $0)
+ (func $0
+  (nop)
+ )
+ (func $1
+  (call $0)
+ )
+)
+;; inline a return_call_ref
+(module
+ (type $none_=>_none (func))
+ (export "func_36_invoker" (func $1))
+ (func $0
+  (return_call_ref
+   (ref.null $none_=>_none)
+  )
+ )
+ (func $1
+  (call $0)
+ )
+)
diff --git a/binaryen/test/passes/instrument-locals_all-features.txt b/binaryen/test/passes/instrument-locals_all-features.txt
deleted file mode 100644
--- a/binaryen/test/passes/instrument-locals_all-features.txt
+++ /dev/null
@@ -1,269 +0,0 @@
-(module
- (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
- (type $i32_i32_i64_=>_i64 (func (param i32 i32 i64) (result i64)))
- (type $i32_i32_f32_=>_f32 (func (param i32 i32 f32) (result f32)))
- (type $i32_i32_f64_=>_f64 (func (param i32 i32 f64) (result f64)))
- (type $i32_i32_v128_=>_v128 (func (param i32 i32 v128) (result v128)))
- (type $i32_i32_funcref_=>_funcref (func (param i32 i32 funcref) (result funcref)))
- (type $i32_i32_externref_=>_externref (func (param i32 i32 externref) (result externref)))
- (type $i32_i32_exnref_=>_exnref (func (param i32 i32 exnref) (result exnref)))
- (type $i32_i32_anyref_=>_anyref (func (param i32 i32 anyref) (result anyref)))
- (type $i32_i32_eqref_=>_eqref (func (param i32 i32 eqref) (result eqref)))
- (type $i32_i32_i31ref_=>_i31ref (func (param i32 i32 i31ref) (result i31ref)))
- (type $none_=>_none (func))
- (import "env" "get_i32" (func $get_i32 (param i32 i32 i32) (result i32)))
- (import "env" "get_i64" (func $get_i64 (param i32 i32 i64) (result i64)))
- (import "env" "get_f32" (func $get_f32 (param i32 i32 f32) (result f32)))
- (import "env" "get_f64" (func $get_f64 (param i32 i32 f64) (result f64)))
- (import "env" "set_i32" (func $set_i32 (param i32 i32 i32) (result i32)))
- (import "env" "set_i64" (func $set_i64 (param i32 i32 i64) (result i64)))
- (import "env" "set_f32" (func $set_f32 (param i32 i32 f32) (result f32)))
- (import "env" "set_f64" (func $set_f64 (param i32 i32 f64) (result f64)))
- (import "env" "get_funcref" (func $get_funcref (param i32 i32 funcref) (result funcref)))
- (import "env" "set_funcref" (func $set_funcref (param i32 i32 funcref) (result funcref)))
- (import "env" "get_externref" (func $get_externref (param i32 i32 externref) (result externref)))
- (import "env" "set_externref" (func $set_externref (param i32 i32 externref) (result externref)))
- (import "env" "get_exnref" (func $get_exnref (param i32 i32 exnref) (result exnref)))
- (import "env" "set_exnref" (func $set_exnref (param i32 i32 exnref) (result exnref)))
- (import "env" "get_anyref" (func $get_anyref (param i32 i32 anyref) (result anyref)))
- (import "env" "set_anyref" (func $set_anyref (param i32 i32 anyref) (result anyref)))
- (import "env" "get_eqref" (func $get_eqref (param i32 i32 eqref) (result eqref)))
- (import "env" "set_eqref" (func $set_eqref (param i32 i32 eqref) (result eqref)))
- (import "env" "get_i31ref" (func $get_i31ref (param i32 i32 i31ref) (result i31ref)))
- (import "env" "set_i31ref" (func $set_i31ref (param i32 i32 i31ref) (result i31ref)))
- (import "env" "get_v128" (func $get_v128 (param i32 i32 v128) (result v128)))
- (import "env" "set_v128" (func $set_v128 (param i32 i32 v128) (result v128)))
- (func $test
-  (local $x i32)
-  (local $y i64)
-  (local $z f32)
-  (local $w f64)
-  (local $F funcref)
-  (local $X externref)
-  (local $E exnref)
-  (local $S v128)
-  (drop
-   (call $get_i32
-    (i32.const 0)
-    (i32.const 0)
-    (local.get $x)
-   )
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (call $get_f32
-    (i32.const 1)
-    (i32.const 2)
-    (local.get $z)
-   )
-  )
-  (drop
-   (call $get_f64
-    (i32.const 2)
-    (i32.const 3)
-    (local.get $w)
-   )
-  )
-  (drop
-   (call $get_funcref
-    (i32.const 3)
-    (i32.const 4)
-    (local.get $F)
-   )
-  )
-  (drop
-   (call $get_externref
-    (i32.const 4)
-    (i32.const 5)
-    (local.get $X)
-   )
-  )
-  (drop
-   (call $get_exnref
-    (i32.const 5)
-    (i32.const 6)
-    (local.get $E)
-   )
-  )
-  (drop
-   (call $get_i32
-    (i32.const 6)
-    (i32.const 0)
-    (local.get $x)
-   )
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (call $get_f32
-    (i32.const 7)
-    (i32.const 2)
-    (local.get $z)
-   )
-  )
-  (drop
-   (call $get_f64
-    (i32.const 8)
-    (i32.const 3)
-    (local.get $w)
-   )
-  )
-  (drop
-   (call $get_funcref
-    (i32.const 9)
-    (i32.const 4)
-    (local.get $F)
-   )
-  )
-  (drop
-   (call $get_externref
-    (i32.const 10)
-    (i32.const 5)
-    (local.get $X)
-   )
-  )
-  (drop
-   (call $get_exnref
-    (i32.const 11)
-    (i32.const 6)
-    (local.get $E)
-   )
-  )
-  (local.set $x
-   (call $set_i32
-    (i32.const 12)
-    (i32.const 0)
-    (i32.const 1)
-   )
-  )
-  (local.set $y
-   (i64.const 2)
-  )
-  (local.set $z
-   (call $set_f32
-    (i32.const 13)
-    (i32.const 2)
-    (f32.const 3.2100000381469727)
-   )
-  )
-  (local.set $w
-   (call $set_f64
-    (i32.const 14)
-    (i32.const 3)
-    (f64.const 4.321)
-   )
-  )
-  (local.set $F
-   (call $set_funcref
-    (i32.const 15)
-    (i32.const 4)
-    (ref.func $test)
-   )
-  )
-  (local.set $X
-   (call $set_externref
-    (i32.const 17)
-    (i32.const 5)
-    (call $get_externref
-     (i32.const 16)
-     (i32.const 5)
-     (local.get $X)
-    )
-   )
-  )
-  (local.set $E
-   (call $set_exnref
-    (i32.const 19)
-    (i32.const 6)
-    (call $get_exnref
-     (i32.const 18)
-     (i32.const 6)
-     (local.get $E)
-    )
-   )
-  )
-  (local.set $x
-   (call $set_i32
-    (i32.const 20)
-    (i32.const 0)
-    (i32.const 11)
-   )
-  )
-  (local.set $y
-   (i64.const 22)
-  )
-  (local.set $z
-   (call $set_f32
-    (i32.const 21)
-    (i32.const 2)
-    (f32.const 33.209999084472656)
-   )
-  )
-  (local.set $w
-   (call $set_f64
-    (i32.const 22)
-    (i32.const 3)
-    (f64.const 44.321)
-   )
-  )
-  (local.set $F
-   (call $set_funcref
-    (i32.const 24)
-    (i32.const 4)
-    (call $get_funcref
-     (i32.const 23)
-     (i32.const 4)
-     (local.get $F)
-    )
-   )
-  )
-  (local.set $X
-   (call $set_externref
-    (i32.const 26)
-    (i32.const 5)
-    (call $get_externref
-     (i32.const 25)
-     (i32.const 5)
-     (local.get $X)
-    )
-   )
-  )
-  (local.set $E
-   (call $set_exnref
-    (i32.const 28)
-    (i32.const 6)
-    (call $get_exnref
-     (i32.const 27)
-     (i32.const 6)
-     (local.get $E)
-    )
-   )
-  )
-  (local.set $F
-   (pop funcref)
-  )
-  (local.set $X
-   (pop externref)
-  )
-  (local.set $E
-   (pop exnref)
-  )
-  (drop
-   (call $get_v128
-    (i32.const 29)
-    (i32.const 7)
-    (local.get $S)
-   )
-  )
-  (local.set $S
-   (call $set_v128
-    (i32.const 30)
-    (i32.const 7)
-    (v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003)
-   )
-  )
- )
-)
diff --git a/binaryen/test/passes/instrument-locals_all-features.wast b/binaryen/test/passes/instrument-locals_all-features.wast
deleted file mode 100644
--- a/binaryen/test/passes/instrument-locals_all-features.wast
+++ /dev/null
@@ -1,54 +0,0 @@
-(module
-  (func $test
-    (local $x i32)
-    (local $y i64)
-    (local $z f32)
-    (local $w f64)
-    (local $F funcref)
-    (local $X externref)
-    (local $E exnref)
-    (local $S v128)
-
-    (drop (local.get $x))
-    (drop (local.get $y))
-    (drop (local.get $z))
-    (drop (local.get $w))
-    (drop (local.get $F))
-    (drop (local.get $X))
-    (drop (local.get $E))
-
-    (drop (local.get $x))
-    (drop (local.get $y))
-    (drop (local.get $z))
-    (drop (local.get $w))
-    (drop (local.get $F))
-    (drop (local.get $X))
-    (drop (local.get $E))
-
-    (local.set $x (i32.const 1))
-    (local.set $y (i64.const 2))
-    (local.set $z (f32.const 3.21))
-    (local.set $w (f64.const 4.321))
-    (local.set $F (ref.func $test))
-    (local.set $X (local.get $X))
-    (local.set $E (local.get $E))
-
-    (local.set $x (i32.const 11))
-    (local.set $y (i64.const 22))
-    (local.set $z (f32.const 33.21))
-    (local.set $w (f64.const 44.321))
-    (local.set $F (local.get $F))
-    (local.set $X (local.get $X))
-    (local.set $E (local.get $E))
-
-    ;; Pop instructions should not be instrumented
-    (local.set $F (pop funcref))
-    (local.set $X (pop externref))
-    (local.set $E (pop exnref))
-
-    ;; Add new instructions here so expected output doesn't change too much, it
-    ;; depends on order of instructions in this file.
-    (drop (local.get $S))
-    (local.set $S (v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003))
-  )
-)
diff --git a/binaryen/test/passes/instrument-locals_all-features_disable-typed-function-references.txt b/binaryen/test/passes/instrument-locals_all-features_disable-typed-function-references.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/instrument-locals_all-features_disable-typed-function-references.txt
@@ -0,0 +1,286 @@
+(module
+ (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
+ (type $i32_i32_i64_=>_i64 (func (param i32 i32 i64) (result i64)))
+ (type $i32_i32_f32_=>_f32 (func (param i32 i32 f32) (result f32)))
+ (type $i32_i32_f64_=>_f64 (func (param i32 i32 f64) (result f64)))
+ (type $i32_i32_v128_=>_v128 (func (param i32 i32 v128) (result v128)))
+ (type $i32_i32_funcref_=>_funcref (func (param i32 i32 funcref) (result funcref)))
+ (type $i32_i32_externref_=>_externref (func (param i32 i32 externref) (result externref)))
+ (type $i32_i32_exnref_=>_exnref (func (param i32 i32 exnref) (result exnref)))
+ (type $i32_i32_anyref_=>_anyref (func (param i32 i32 anyref) (result anyref)))
+ (type $i32_i32_eqref_=>_eqref (func (param i32 i32 eqref) (result eqref)))
+ (type $i32_i32_i31ref_=>_i31ref (func (param i32 i32 i31ref) (result i31ref)))
+ (type $none_=>_none (func))
+ (import "env" "get_i32" (func $get_i32 (param i32 i32 i32) (result i32)))
+ (import "env" "get_i64" (func $get_i64 (param i32 i32 i64) (result i64)))
+ (import "env" "get_f32" (func $get_f32 (param i32 i32 f32) (result f32)))
+ (import "env" "get_f64" (func $get_f64 (param i32 i32 f64) (result f64)))
+ (import "env" "set_i32" (func $set_i32 (param i32 i32 i32) (result i32)))
+ (import "env" "set_i64" (func $set_i64 (param i32 i32 i64) (result i64)))
+ (import "env" "set_f32" (func $set_f32 (param i32 i32 f32) (result f32)))
+ (import "env" "set_f64" (func $set_f64 (param i32 i32 f64) (result f64)))
+ (import "env" "get_funcref" (func $get_funcref (param i32 i32 funcref) (result funcref)))
+ (import "env" "set_funcref" (func $set_funcref (param i32 i32 funcref) (result funcref)))
+ (import "env" "get_externref" (func $get_externref (param i32 i32 externref) (result externref)))
+ (import "env" "set_externref" (func $set_externref (param i32 i32 externref) (result externref)))
+ (import "env" "get_exnref" (func $get_exnref (param i32 i32 exnref) (result exnref)))
+ (import "env" "set_exnref" (func $set_exnref (param i32 i32 exnref) (result exnref)))
+ (import "env" "get_anyref" (func $get_anyref (param i32 i32 anyref) (result anyref)))
+ (import "env" "set_anyref" (func $set_anyref (param i32 i32 anyref) (result anyref)))
+ (import "env" "get_eqref" (func $get_eqref (param i32 i32 eqref) (result eqref)))
+ (import "env" "set_eqref" (func $set_eqref (param i32 i32 eqref) (result eqref)))
+ (import "env" "get_i31ref" (func $get_i31ref (param i32 i32 i31ref) (result i31ref)))
+ (import "env" "set_i31ref" (func $set_i31ref (param i32 i32 i31ref) (result i31ref)))
+ (import "env" "get_v128" (func $get_v128 (param i32 i32 v128) (result v128)))
+ (import "env" "set_v128" (func $set_v128 (param i32 i32 v128) (result v128)))
+ (func $test
+  (local $x i32)
+  (local $y i64)
+  (local $z f32)
+  (local $w f64)
+  (local $F funcref)
+  (local $X externref)
+  (local $E exnref)
+  (local $S v128)
+  (drop
+   (call $get_i32
+    (i32.const 0)
+    (i32.const 0)
+    (local.get $x)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (call $get_f32
+    (i32.const 1)
+    (i32.const 2)
+    (local.get $z)
+   )
+  )
+  (drop
+   (call $get_f64
+    (i32.const 2)
+    (i32.const 3)
+    (local.get $w)
+   )
+  )
+  (drop
+   (call $get_funcref
+    (i32.const 3)
+    (i32.const 4)
+    (local.get $F)
+   )
+  )
+  (drop
+   (call $get_externref
+    (i32.const 4)
+    (i32.const 5)
+    (local.get $X)
+   )
+  )
+  (drop
+   (call $get_exnref
+    (i32.const 5)
+    (i32.const 6)
+    (local.get $E)
+   )
+  )
+  (drop
+   (call $get_i32
+    (i32.const 6)
+    (i32.const 0)
+    (local.get $x)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (call $get_f32
+    (i32.const 7)
+    (i32.const 2)
+    (local.get $z)
+   )
+  )
+  (drop
+   (call $get_f64
+    (i32.const 8)
+    (i32.const 3)
+    (local.get $w)
+   )
+  )
+  (drop
+   (call $get_funcref
+    (i32.const 9)
+    (i32.const 4)
+    (local.get $F)
+   )
+  )
+  (drop
+   (call $get_externref
+    (i32.const 10)
+    (i32.const 5)
+    (local.get $X)
+   )
+  )
+  (drop
+   (call $get_exnref
+    (i32.const 11)
+    (i32.const 6)
+    (local.get $E)
+   )
+  )
+  (local.set $x
+   (call $set_i32
+    (i32.const 12)
+    (i32.const 0)
+    (i32.const 1)
+   )
+  )
+  (local.set $y
+   (i64.const 2)
+  )
+  (local.set $z
+   (call $set_f32
+    (i32.const 13)
+    (i32.const 2)
+    (f32.const 3.2100000381469727)
+   )
+  )
+  (local.set $w
+   (call $set_f64
+    (i32.const 14)
+    (i32.const 3)
+    (f64.const 4.321)
+   )
+  )
+  (local.set $F
+   (ref.func $test)
+  )
+  (local.set $X
+   (call $set_externref
+    (i32.const 16)
+    (i32.const 5)
+    (call $get_externref
+     (i32.const 15)
+     (i32.const 5)
+     (local.get $X)
+    )
+   )
+  )
+  (local.set $E
+   (call $set_exnref
+    (i32.const 18)
+    (i32.const 6)
+    (call $get_exnref
+     (i32.const 17)
+     (i32.const 6)
+     (local.get $E)
+    )
+   )
+  )
+  (local.set $x
+   (call $set_i32
+    (i32.const 19)
+    (i32.const 0)
+    (i32.const 11)
+   )
+  )
+  (local.set $y
+   (i64.const 22)
+  )
+  (local.set $z
+   (call $set_f32
+    (i32.const 20)
+    (i32.const 2)
+    (f32.const 33.209999084472656)
+   )
+  )
+  (local.set $w
+   (call $set_f64
+    (i32.const 21)
+    (i32.const 3)
+    (f64.const 44.321)
+   )
+  )
+  (local.set $F
+   (call $set_funcref
+    (i32.const 23)
+    (i32.const 4)
+    (call $get_funcref
+     (i32.const 22)
+     (i32.const 4)
+     (local.get $F)
+    )
+   )
+  )
+  (local.set $X
+   (call $set_externref
+    (i32.const 25)
+    (i32.const 5)
+    (call $get_externref
+     (i32.const 24)
+     (i32.const 5)
+     (local.get $X)
+    )
+   )
+  )
+  (local.set $E
+   (call $set_exnref
+    (i32.const 27)
+    (i32.const 6)
+    (call $get_exnref
+     (i32.const 26)
+     (i32.const 6)
+     (local.get $E)
+    )
+   )
+  )
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (local.set $F
+     (pop funcref)
+    )
+   )
+  )
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (local.set $X
+     (pop externref)
+    )
+   )
+  )
+  (try
+   (do
+    (nop)
+   )
+   (catch
+    (local.set $E
+     (pop exnref)
+    )
+   )
+  )
+  (drop
+   (call $get_v128
+    (i32.const 28)
+    (i32.const 7)
+    (local.get $S)
+   )
+  )
+  (local.set $S
+   (call $set_v128
+    (i32.const 29)
+    (i32.const 7)
+    (v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/instrument-locals_all-features_disable-typed-function-references.wast b/binaryen/test/passes/instrument-locals_all-features_disable-typed-function-references.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/instrument-locals_all-features_disable-typed-function-references.wast
@@ -0,0 +1,69 @@
+(module
+  (func $test
+    (local $x i32)
+    (local $y i64)
+    (local $z f32)
+    (local $w f64)
+    (local $F funcref)
+    (local $X externref)
+    (local $E exnref)
+    (local $S v128)
+
+    (drop (local.get $x))
+    (drop (local.get $y))
+    (drop (local.get $z))
+    (drop (local.get $w))
+    (drop (local.get $F))
+    (drop (local.get $X))
+    (drop (local.get $E))
+
+    (drop (local.get $x))
+    (drop (local.get $y))
+    (drop (local.get $z))
+    (drop (local.get $w))
+    (drop (local.get $F))
+    (drop (local.get $X))
+    (drop (local.get $E))
+
+    (local.set $x (i32.const 1))
+    (local.set $y (i64.const 2))
+    (local.set $z (f32.const 3.21))
+    (local.set $w (f64.const 4.321))
+    (local.set $F (ref.func $test))
+    (local.set $X (local.get $X))
+    (local.set $E (local.get $E))
+
+    (local.set $x (i32.const 11))
+    (local.set $y (i64.const 22))
+    (local.set $z (f32.const 33.21))
+    (local.set $w (f64.const 44.321))
+    (local.set $F (local.get $F))
+    (local.set $X (local.get $X))
+    (local.set $E (local.get $E))
+
+    ;; Pop instructions should not be instrumented
+    (try
+      (do)
+      (catch
+        (local.set $F (pop funcref))
+      )
+    )
+    (try
+      (do)
+      (catch
+        (local.set $X (pop externref))
+      )
+    )
+    (try
+      (do)
+      (catch
+        (local.set $E (pop exnref))
+      )
+    )
+
+    ;; Add new instructions here so expected output doesn't change too much, it
+    ;; depends on order of instructions in this file.
+    (drop (local.get $S))
+    (local.set $S (v128.const i32x4 0x00000000 0x00000001 0x00000002 0x00000003))
+  )
+)
diff --git a/binaryen/test/passes/interesting-pass-mix.txt b/binaryen/test/passes/interesting-pass-mix.txt
--- a/binaryen/test/passes/interesting-pass-mix.txt
+++ b/binaryen/test/passes/interesting-pass-mix.txt
@@ -17,8 +17,7 @@
   (i32.const 1)
  )
  (func $ifs (param $0 i32) (result i32)
-  (if (result i32)
-   (local.get $0)
+  (select
    (select
     (i32.const 2)
     (i32.const 3)
@@ -29,6 +28,7 @@
     (i32.const 5)
     (local.get $0)
    )
+   (local.get $0)
   )
  )
  (func $loops (param $0 i32)
@@ -41,14 +41,16 @@
   )
   (loop $shape$4$continue
    (call $trivial)
-   (br_if $shape$4$continue
+   (if
     (local.get $0)
+    (br $shape$4$continue)
    )
   )
   (loop $shape$6$continue
    (call $trivial)
-   (br_if $shape$6$continue
+   (if
     (local.get $0)
+    (br $shape$6$continue)
    )
   )
  )
@@ -119,8 +121,9 @@
    (call $before-and-after
     (i32.const 9)
    )
-   (br_if $shape$4$continue
+   (if
     (local.get $0)
+    (br $shape$4$continue)
    )
   )
   (call $before-and-after
@@ -187,9 +190,12 @@
   )
   (block $block$7$break
    (block $switch$3$default
-    (br_table $block$7$break $block$7$break $block$7$break $switch$3$default
-     (local.get $0)
+    (block $switch$3$case$7
+     (br_table $switch$3$case$7 $switch$3$case$7 $switch$3$case$7 $switch$3$default
+      (local.get $0)
+     )
     )
+    (br $block$7$break)
    )
    (call $switch
     (i32.const 2)
@@ -212,8 +218,9 @@
     (call $if-br-wat
      (i32.const 1)
     )
-    (br_if $block$2$break
+    (if
      (local.get $0)
+     (br $block$2$break)
     )
    )
    (call $if-br-wat
diff --git a/binaryen/test/passes/legalize-js-interface-minimally.txt b/binaryen/test/passes/legalize-js-interface-minimally.txt
--- a/binaryen/test/passes/legalize-js-interface-minimally.txt
+++ b/binaryen/test/passes/legalize-js-interface-minimally.txt
@@ -1,8 +1,8 @@
 (module
  (type $none_=>_i64 (func (result i64)))
  (type $i32_=>_none (func (param i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
  (type $i64_=>_none (func (param i64)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
  (type $none_=>_i32 (func (result i32)))
  (import "env" "imported" (func $imported (result i64)))
  (import "env" "setTempRet0" (func $setTempRet0 (param i32)))
diff --git a/binaryen/test/passes/memory-packing_all-features.txt b/binaryen/test/passes/memory-packing_all-features.txt
--- a/binaryen/test/passes/memory-packing_all-features.txt
+++ b/binaryen/test/passes/memory-packing_all-features.txt
@@ -1,15 +1,19 @@
 (module
- (import "env" "memory" (memory $0 2048 2048))
  (import "env" "memoryBase" (global $memoryBase i32))
+ (memory $0 2048 2048)
 )
 (module
- (import "env" "memory" (memory $0 2048 2048))
  (import "env" "memoryBase" (global $memoryBase i32))
+ (memory $0 2048 2048)
 )
 (module
- (type $none_=>_none (func))
- (import "env" "memory" (memory $0 2048 2048))
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (memory $0 2048 2048)
  (data (global.get $memoryBase) "waka this cannot be optimized\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00we don\'t know where it will go")
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 1)
  (data (i32.const 1024) "waka this CAN be optimized")
  (data (i32.const 1107) "we DO know where it will go")
  (data (i32.const 2057) "zeros before")
@@ -17,7 +21,6 @@
  (data (i32.const 4000) "zeros\00in\00the\00middle")
  (data (i32.const 4035) "nice skip here")
  (data (i32.const 4066) "another\00but no")
- (import "env" "memoryBase" (global $memoryBase i32))
  (func $nonzero-size-init-of-active-will-trap
   (block
    (drop
@@ -64,7 +67,7 @@
 )
 (module
  (type $none_=>_none (func))
- (import "env" "memory" (memory $0 2048 2048))
+ (memory $0 2048 2048)
  (data passive "zeroes at start")
  (data passive "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00zeroes at start")
  (data passive "\00\00\00few zeroes at start")
@@ -82,13 +85,13 @@
  (data passive "more")
  (data passive "zeroes")
  (data passive "no zeroes")
+ (global $__mem_segment_drop_state (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_0 (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_1 (mut i32) (i32.const 0))
- (global $__mem_segment_drop_state_2 (mut i32) (i32.const 0))
  (func $zeroes-at-start
   (block
    (if
-    (global.get $__mem_segment_drop_state_0)
+    (global.get $__mem_segment_drop_state)
     (unreachable)
    )
    (memory.fill
@@ -103,7 +106,7 @@
    )
   )
   (block
-   (global.set $__mem_segment_drop_state_0
+   (global.set $__mem_segment_drop_state
     (i32.const 1)
    )
    (data.drop 0)
@@ -267,7 +270,7 @@
  (func $even-more-zeroes
   (block
    (if
-    (global.get $__mem_segment_drop_state_1)
+    (global.get $__mem_segment_drop_state_0)
     (unreachable)
    )
    (memory.fill
@@ -307,7 +310,7 @@
    )
   )
   (block
-   (global.set $__mem_segment_drop_state_1
+   (global.set $__mem_segment_drop_state_0
     (i32.const 1)
    )
    (data.drop 13)
@@ -318,7 +321,7 @@
  (func $only-zeroes
   (block
    (if
-    (global.get $__mem_segment_drop_state_2)
+    (global.get $__mem_segment_drop_state_1)
     (unreachable)
    )
    (memory.fill
@@ -327,7 +330,7 @@
     (i32.const 30)
    )
   )
-  (global.set $__mem_segment_drop_state_2
+  (global.set $__mem_segment_drop_state_1
    (i32.const 1)
   )
  )
@@ -363,7 +366,8 @@
 )
 (module
  (type $none_=>_none (func))
- (import "env" "memory" (memory $0 2048 2048))
+ (import "env" "param" (global $param i32))
+ (memory $0 2048 2048)
  (data passive "even")
  (data passive "more")
  (data passive "zeroes")
@@ -396,7 +400,7 @@
  (data passive "even")
  (data passive "more")
  (data passive "zeroes")
- (import "env" "param" (global $param i32))
+ (global $__mem_segment_drop_state (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_0 (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_1 (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_2 (mut i32) (i32.const 0))
@@ -404,7 +408,6 @@
  (global $__mem_segment_drop_state_4 (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_5 (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_6 (mut i32) (i32.const 0))
- (global $__mem_segment_drop_state_7 (mut i32) (i32.const 0))
  (func $nonconst-dest
   (local $0 i32)
   (block
@@ -412,7 +415,7 @@
     (global.get $param)
    )
    (if
-    (global.get $__mem_segment_drop_state_0)
+    (global.get $__mem_segment_drop_state)
     (unreachable)
    )
    (memory.fill
@@ -470,7 +473,7 @@
    )
   )
   (block
-   (global.set $__mem_segment_drop_state_0
+   (global.set $__mem_segment_drop_state
     (i32.const 1)
    )
    (data.drop 0)
@@ -497,7 +500,7 @@
  (func $partial-skip-start
   (block
    (if
-    (global.get $__mem_segment_drop_state_1)
+    (global.get $__mem_segment_drop_state_0)
     (unreachable)
    )
    (memory.fill
@@ -537,7 +540,7 @@
    )
   )
   (block
-   (global.set $__mem_segment_drop_state_1
+   (global.set $__mem_segment_drop_state_0
     (i32.const 1)
    )
    (data.drop 5)
@@ -587,7 +590,7 @@
  (func $partial-skip-end
   (block
    (if
-    (global.get $__mem_segment_drop_state_2)
+    (global.get $__mem_segment_drop_state_1)
     (unreachable)
    )
    (memory.fill
@@ -627,7 +630,7 @@
    )
   )
   (block
-   (global.set $__mem_segment_drop_state_2
+   (global.set $__mem_segment_drop_state_1
     (i32.const 1)
    )
    (data.drop 11)
@@ -638,7 +641,7 @@
  (func $full-skip-end
   (block
    (if
-    (global.get $__mem_segment_drop_state_3)
+    (global.get $__mem_segment_drop_state_2)
     (unreachable)
    )
    (memory.fill
@@ -673,7 +676,7 @@
    )
   )
   (block
-   (global.set $__mem_segment_drop_state_3
+   (global.set $__mem_segment_drop_state_2
     (i32.const 1)
    )
    (data.drop 14)
@@ -684,7 +687,7 @@
  (func $slice-zeroes
   (block
    (if
-    (global.get $__mem_segment_drop_state_4)
+    (global.get $__mem_segment_drop_state_3)
     (unreachable)
    )
    (memory.fill
@@ -694,7 +697,7 @@
    )
   )
   (block
-   (global.set $__mem_segment_drop_state_4
+   (global.set $__mem_segment_drop_state_3
     (i32.const 1)
    )
    (data.drop 17)
@@ -724,12 +727,12 @@
       (i32.const 16)
      )
     )
-    (global.get $__mem_segment_drop_state_5)
+    (global.get $__mem_segment_drop_state_4)
    )
    (unreachable)
   )
   (block
-   (global.set $__mem_segment_drop_state_5
+   (global.set $__mem_segment_drop_state_4
     (i32.const 1)
    )
    (data.drop 23)
@@ -747,7 +750,7 @@
       (i32.const 16)
      )
     )
-    (global.get $__mem_segment_drop_state_6)
+    (global.get $__mem_segment_drop_state_5)
    )
    (unreachable)
   )
@@ -807,12 +810,12 @@
       (i32.const 16)
      )
     )
-    (global.get $__mem_segment_drop_state_7)
+    (global.get $__mem_segment_drop_state_6)
    )
    (unreachable)
   )
   (block
-   (global.set $__mem_segment_drop_state_7
+   (global.set $__mem_segment_drop_state_6
     (i32.const 1)
    )
    (data.drop 29)
@@ -823,7 +826,7 @@
 )
 (module
  (type $none_=>_none (func))
- (import "env" "memory" (memory $0 2048 2048))
+ (memory $0 2048 2048)
  (data passive "hi")
  (data passive "even")
  (data passive "hi")
@@ -834,10 +837,10 @@
  (data passive "hi")
  (data passive "even")
  (data passive "hi")
+ (global $__mem_segment_drop_state (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_0 (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_1 (mut i32) (i32.const 0))
  (global $__mem_segment_drop_state_2 (mut i32) (i32.const 0))
- (global $__mem_segment_drop_state_3 (mut i32) (i32.const 0))
  (func $zero-length-init-zeroes
   (if
    (i32.or
@@ -848,12 +851,12 @@
       (i32.const 16)
      )
     )
-    (global.get $__mem_segment_drop_state_0)
+    (global.get $__mem_segment_drop_state)
    )
    (unreachable)
   )
   (block
-   (global.set $__mem_segment_drop_state_0
+   (global.set $__mem_segment_drop_state
     (i32.const 1)
    )
    (data.drop 0)
@@ -871,12 +874,12 @@
       (i32.const 16)
      )
     )
-    (global.get $__mem_segment_drop_state_1)
+    (global.get $__mem_segment_drop_state_0)
    )
    (unreachable)
   )
   (block
-   (global.set $__mem_segment_drop_state_1
+   (global.set $__mem_segment_drop_state_0
     (i32.const 1)
    )
    (data.drop 3)
@@ -894,12 +897,12 @@
       (i32.const 16)
      )
     )
-    (global.get $__mem_segment_drop_state_2)
+    (global.get $__mem_segment_drop_state_1)
    )
    (unreachable)
   )
   (block
-   (global.set $__mem_segment_drop_state_2
+   (global.set $__mem_segment_drop_state_1
     (i32.const 1)
    )
    (data.drop 6)
@@ -916,12 +919,12 @@
       (i32.const 16)
      )
     )
-    (global.get $__mem_segment_drop_state_3)
+    (global.get $__mem_segment_drop_state_2)
    )
    (unreachable)
   )
   (block
-   (global.set $__mem_segment_drop_state_3
+   (global.set $__mem_segment_drop_state_2
     (i32.const 1)
    )
    (data.drop 8)
@@ -931,7 +934,7 @@
 )
 (module
  (type $none_=>_none (func))
- (import "env" "memory" (memory $0 2048 2048))
+ (memory $0 2048 2048)
  (data passive "a")
  (data passive "a")
  (data passive "a")
@@ -1504,4 +1507,68 @@
    (data.drop 62)
   )
  )
+)
+(module
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+ (data (i32.const 1024) "\00")
+)
+(module
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+)
+(module
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+)
+(module
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+ (data (i32.const 1024) "\00")
+ (data (i32.const 4096) "\00")
+)
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+ (data (global.get $memoryBase) "\00")
+)
+(module
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (memory $0 1 1)
+ (data (i32.const 1024) "\00")
+ (data (global.get $memoryBase) "x")
+)
+(module
+ (type $none_=>_none (func))
+ (memory $0 1 1)
+ (data passive "skipped")
+ (data passive "included")
+ (global $__mem_segment_drop_state (mut i32) (i32.const 0))
+ (export "func_54" (func $0))
+ (func $0
+  (if
+   (global.get $__mem_segment_drop_state)
+   (unreachable)
+  )
+  (memory.fill
+   (i32.const 0)
+   (i32.const 0)
+   (i32.const 30)
+  )
+  (memory.init 1
+   (i32.const 30)
+   (i32.const 0)
+   (i32.const 8)
+  )
+ )
+)
+(module
+ (import "env" "memory" (memory $0 1 1))
+ (data (i32.const 1024) "x")
+ (data (i32.const 2048) "\00")
+)
+(module
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
 )
diff --git a/binaryen/test/passes/memory-packing_all-features.wast b/binaryen/test/passes/memory-packing_all-features.wast
--- a/binaryen/test/passes/memory-packing_all-features.wast
+++ b/binaryen/test/passes/memory-packing_all-features.wast
@@ -1,21 +1,25 @@
 (module
-  (import "env" "memory" (memory $0 2048 2048))
+  (memory $0 2048 2048)
   (import "env" "memoryBase" (global $memoryBase i32))
   ;; nothing
 )
 
 (module
-  (import "env" "memory" (memory $0 2048 2048))
+  (memory $0 2048 2048)
   (import "env" "memoryBase" (global $memoryBase i32))
   (data (i32.const 4066) "") ;; empty
 )
 
 (module
-  (import "env" "memory" (memory $0 2048 2048))
+  (memory $0 2048 2048)
   (import "env" "memoryBase" (global $memoryBase i32))
 
   (data (global.get $memoryBase) "waka this cannot be optimized\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00we don't know where it will go")
+)
 
+(module
+  (memory 1 1)
+
   (data (i32.const 1024) "waka this CAN be optimized\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00we DO know where it will go")
 
   (data (i32.const 2000) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00zeros before")
@@ -53,7 +57,7 @@
 )
 
 (module
-  (import "env" "memory" (memory $0 2048 2048))
+  (memory $0 2048 2048)
 
   (data passive "not referenced, delete me") ;; 0
 
@@ -267,7 +271,7 @@
 )
 
 (module
-  (import "env" "memory" (memory $0 2048 2048))
+  (memory $0 2048 2048)
   (import "env" "param" (global $param i32))
 
   (data passive "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00even\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00more\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00zeroes\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") ;; 0
@@ -436,7 +440,7 @@
 )
 
 (module
-  (import "env" "memory" (memory $0 2048 2048))
+  (memory $0 2048 2048)
   (data passive "hi\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00even\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00hi") ;; 0
 
   (func $zero-length-init-zeroes
@@ -483,7 +487,7 @@
 )
 
 (module
-  (import "env" "memory" (memory $0 2048 2048))
+  (memory $0 2048 2048)
   (data passive "a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00a") ;; 64 ranges of zeroes
 
   (func $init-lots
@@ -494,4 +498,61 @@
     )
     (data.drop 0)
   )
+)
+(module
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+ (data (i32.const 1024) "\00") ;; this tramples the "x", and so must be kept.
+)
+(module
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+ (data (i32.const 1025) "\00")
+)
+(module
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+ (data (i32.const 1023) "\00")
+)
+(module
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+ (data (i32.const 1024) "\00") ;; when we see one bad thing, we give up
+ (data (i32.const 4096) "\00")
+)
+(module
+ (memory $0 1 1)
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (data (i32.const 1024) "x")
+ (data (global.get $memoryBase) "\00") ;; this could trample, or not
+)
+(module
+ (memory $0 1 1)
+ (import "env" "memoryBase" (global $memoryBase i32))
+ (data (i32.const 1024) "\00") ;; this could trample, or not
+ (data (global.get $memoryBase) "x")
+)
+(module
+ (memory $0 1 1)
+ (data passive "skipped\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00included")
+ (export "func_54" (func $0))
+ (func $0
+  (memory.init 0
+   (i32.const 0)
+   (i32.const 7)
+   (i32.const 38)
+  )
+ )
+)
+(module
+ ;; we can't optimize on an imported memory without zeroFilledMemory being set.
+ (import "env" "memory" (memory $0 1 1))
+ (data (i32.const 1024) "x")
+ (data (i32.const 2048) "\00")
+)
+(module
+ ;; we can when not imported
+ (memory $0 1 1)
+ (data (i32.const 1024) "x")
+ (data (i32.const 2048) "\00")
 )
diff --git a/binaryen/test/passes/memory-packing_all-features_zero-filled-memory.txt b/binaryen/test/passes/memory-packing_all-features_zero-filled-memory.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/memory-packing_all-features_zero-filled-memory.txt
@@ -0,0 +1,4 @@
+(module
+ (import "env" "memory" (memory $0 1 1))
+ (data (i32.const 1024) "x")
+)
diff --git a/binaryen/test/passes/memory-packing_all-features_zero-filled-memory.wast b/binaryen/test/passes/memory-packing_all-features_zero-filled-memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/memory-packing_all-features_zero-filled-memory.wast
@@ -0,0 +1,6 @@
+(module
+ ;; we can optimize on an imported memory with zeroFilledMemory being set.
+ (import "env" "memory" (memory $0 1 1))
+ (data (i32.const 1024) "x")
+ (data (i32.const 1023) "\00")
+)
diff --git a/binaryen/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.txt b/binaryen/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.txt
@@ -0,0 +1,168 @@
+(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
+  (local $0 i64)
+  (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)
+  )
+  (local.set $0
+   (i64.extend_i32_u
+    (memory.size)
+   )
+  )
+  (local.set $0
+   (i64.extend_i32_u
+    (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/binaryen/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast b/binaryen/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/memory64-lowering_enable-memory64_enable-bulk-memory.wast
@@ -0,0 +1,31 @@
+(module
+ (memory $0 i64 1 1)
+ (data (i32.const 0) "\00\00\00\00\00\00\00\00\00\00")
+ (func $func_1
+  (local i64)
+  (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))
+  (local.set 0 (memory.size))
+  (local.set 0 (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))
+ )
+)
diff --git a/binaryen/test/passes/multi_line_table_dwarf.bin.txt b/binaryen/test/passes/multi_line_table_dwarf.bin.txt
--- a/binaryen/test/passes/multi_line_table_dwarf.bin.txt
+++ b/binaryen/test/passes/multi_line_table_dwarf.bin.txt
@@ -424,10 +424,10 @@
  (type $none_=>_none (func))
  (type $none_=>_i32 (func (result i32)))
  (import "env" "memory" (memory $mimport$0 0))
- (import "env" "__indirect_function_table" (table $timport$1 0 funcref))
- (import "env" "__stack_pointer" (global $gimport$2 (mut i32)))
- (import "env" "__memory_base" (global $gimport$3 i32))
- (import "env" "__table_base" (global $gimport$4 i32))
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
+ (import "env" "__stack_pointer" (global $gimport$0 (mut i32)))
+ (import "env" "__memory_base" (global $gimport$1 i32))
+ (import "env" "__table_base" (global $gimport$2 i32))
  (global $global$0 i32 (i32.const 0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "__wasm_apply_relocs" (func $__wasm_apply_relocs))
diff --git a/binaryen/test/passes/optimize-instructions_all-features.txt b/binaryen/test/passes/optimize-instructions_all-features.txt
--- a/binaryen/test/passes/optimize-instructions_all-features.txt
+++ b/binaryen/test/passes/optimize-instructions_all-features.txt
@@ -1,4664 +1,5707 @@
 (module
  (type $i32_i32_=>_none (func (param i32 i32)))
- (type $i32_=>_i32 (func (param i32) (result i32)))
- (type $none_=>_i32 (func (result i32)))
- (type $i32_i64_=>_none (func (param i32 i64)))
- (type $none_=>_none (func))
- (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
- (type $i32_=>_none (func (param i32)))
- (type $none_=>_i64 (func (result i64)))
- (type $i64_=>_i64 (func (param i64) (result i64)))
- (type $i32_i32_i64_i64_=>_none (func (param i32 i32 i64 i64)))
- (type $i32_i64_f32_=>_none (func (param i32 i64 f32)))
- (type $i32_i64_f32_f64_=>_none (func (param i32 i64 f32 f64)))
- (type $none_=>_anyref (func (result anyref)))
- (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
- (type $i32_i32_i32_f64_=>_none (func (param i32 i32 i32 f64)))
- (type $i32_i32_f64_f64_=>_none (func (param i32 i32 f64 f64)))
- (type $i32_i64_f64_i32_=>_none (func (param i32 i64 f64 i32)))
- (type $f32_f64_=>_none (func (param f32 f64)))
- (type $none_=>_f64 (func (result f64)))
- (memory $0 0)
- (export "load-off-2" (func $load-off-2))
- (func $f (param $i1 i32) (param $i2 i64)
-  (if
-   (i32.eqz
-    (local.get $i1)
-   )
-   (drop
-    (i32.const 10)
-   )
-  )
-  (if
-   (local.get $i1)
-   (drop
-    (i32.const 12)
-   )
-   (drop
-    (i32.const 11)
-   )
-  )
-  (if
-   (i64.eqz
-    (local.get $i2)
-   )
-   (drop
-    (i32.const 11)
-   )
-   (drop
-    (i32.const 12)
-   )
-  )
-  (drop
-   (i32.le_u
-    (i32.const 1)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.lt_u
-    (i32.const 1)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.ge_u
-    (i32.const 1)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.gt_u
-    (i32.const 1)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.le_u
-    (i32.const 1)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.lt_u
-    (i32.const 1)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.ge_u
-    (i32.const 1)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.gt_u
-    (i32.const 1)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.eqz
-    (f32.gt
-     (f32.const 1)
-     (f32.const 2)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (f32.ge
-     (f32.const 1)
-     (f32.const 2)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (f32.lt
-     (f32.const 1)
-     (f32.const 2)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (f32.le
-     (f32.const 1)
-     (f32.const 2)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (f64.gt
-     (f64.const 1)
-     (f64.const 2)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (f64.ge
-     (f64.const 1)
-     (f64.const 2)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (f64.lt
-     (f64.const 1)
-     (f64.const 2)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (f64.le
-     (f64.const 1)
-     (f64.const 2)
-    )
-   )
-  )
-  (drop
-   (f32.ne
-    (f32.const 1)
-    (f32.const 2)
-   )
-  )
-  (drop
-   (f32.eq
-    (f32.const 1)
-    (f32.const 2)
-   )
-  )
-  (drop
-   (f64.ne
-    (f64.const 1)
-    (f64.const 2)
-   )
-  )
-  (drop
-   (f64.eq
-    (f64.const 1)
-    (f64.const 2)
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.const 100)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.const 0)
-    (i32.const 100)
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.const 100)
-   )
-  )
-  (drop
-   (i64.eq
-    (i64.const 0)
-    (i64.const 100)
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.const 0)
-   )
-  )
-  (if
-   (i32.const 123)
-   (nop)
-  )
-  (if
-   (try (result i32)
-    (do
-     (i32.const 123)
-    )
-    (catch
-     (drop
-      (pop exnref)
-     )
-     (i32.const 456)
-    )
-   )
-   (nop)
-  )
-  (drop
-   (select
-    (i32.const 102)
-    (i32.const 101)
-    (local.get $i1)
-   )
-  )
-  (drop
-   (select
-    (local.tee $i1
-     (i32.const 103)
-    )
-    (local.tee $i1
-     (i32.const 104)
-    )
-    (i32.eqz
-     (local.get $i1)
-    )
-   )
-  )
-  (drop
-   (i32.const 0)
-  )
- )
- (func $load-store
-  (drop
-   (i32.load8_u
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.load8_u
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.load8_s
-     (i32.const 2)
-    )
-    (i32.const 254)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.load8_u
-     (i32.const 3)
-    )
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.load16_u
-    (i32.const 4)
-   )
-  )
-  (drop
-   (i32.load16_u
-    (i32.const 5)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.load16_s
-     (i32.const 6)
-    )
-    (i32.const 65534)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.load16_u
-     (i32.const 7)
-    )
-    (i32.const 1)
-   )
-  )
-  (i32.store8
-   (i32.const 8)
-   (i32.const -1)
-  )
-  (i32.store8
-   (i32.const 9)
-   (i32.and
-    (i32.const -2)
-    (i32.const 254)
-   )
-  )
-  (i32.store16
-   (i32.const 10)
-   (i32.const -3)
-  )
-  (i32.store16
-   (i32.const 11)
-   (i32.and
-    (i32.const -4)
-    (i32.const 65534)
-   )
-  )
-  (i64.store8
-   (i32.const 11)
-   (i64.const 1)
-  )
-  (i64.store16
-   (i32.const 11)
-   (i64.const 2)
-  )
-  (i64.store32
-   (i32.const 11)
-   (i64.const 3)
-  )
- )
- (func $and-neg1
-  (drop
-   (i32.const 100)
-  )
-  (drop
-   (i32.and
-    (i32.const 100)
-    (i32.const 1)
-   )
-  )
- )
- (func $and-pos1
-  (drop
-   (i32.eqz
-    (i32.const 1000)
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.const 1000)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.const 100)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.lt_u
-    (i32.const 2000)
-    (i32.const 3000)
-   )
-  )
- )
- (func $canonicalize (param $x i32) (param $y i32) (param $fx f64) (param $fy f64)
-  (drop
-   (i32.and
-    (unreachable)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.const 1)
-    (unreachable)
-   )
-  )
-  (drop
-   (i32.div_s
-    (unreachable)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.div_s
-    (i32.const 1)
-    (unreachable)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.const 1)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (i32.const 3)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (i32.const 4)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.and
-    (local.tee $x
-     (i32.const -4)
-    )
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.and
-    (block $block (result i32)
-     (i32.const -5)
-    )
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.and
-    (block $block4 (result i32)
-     (i32.const -6)
-    )
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.and
-    (block $block5 (result i32)
-     (i32.const 5)
-    )
-    (loop $loop-in (result i32)
-     (i32.const 6)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (block $block7 (result i32)
-     (i32.const 8)
-    )
-    (loop $loop-in6 (result i32)
-     (i32.const 7)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (block $block9 (result i32)
-     (i32.const 10)
-    )
-    (loop $loop-in8 (result i32)
-     (call $and-pos1)
-     (i32.const 9)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (block $block11 (result i32)
-     (call $and-pos1)
-     (i32.const 12)
-    )
-    (loop $loop-in10 (result i32)
-     (i32.const 11)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (loop $loop-in12 (result i32)
-     (call $and-pos1)
-     (i32.const 13)
-    )
-    (block $block13 (result i32)
-     (call $and-pos1)
-     (i32.const 14)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (block $block14 (result i32)
-     (call $and-pos1)
-     (i32.const 14)
-    )
-    (loop $loop-in15 (result i32)
-     (call $and-pos1)
-     (i32.const 13)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (block $block16 (result i32)
-     (i32.const 15)
-    )
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.and
-    (block $block17 (result i32)
-     (i32.const 15)
-    )
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.gt_u
-     (i32.const 16)
-     (i32.const 17)
-    )
-    (i32.gt_u
-     (i32.const 18)
-     (i32.const 19)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (i32.gt_u
-     (i32.const 20)
-     (i32.const 21)
-    )
-    (i32.gt_u
-     (i32.const 22)
-     (i32.const 23)
-    )
-   )
-  )
-  (drop
-   (i32.add
-    (i32.ctz
-     (local.get $x)
-    )
-    (i32.ctz
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.add
-    (i32.ctz
-     (local.get $y)
-    )
-    (i32.ctz
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (i32.add
-    (i32.ctz
-     (local.get $x)
-    )
-    (i32.eqz
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.add
-    (i32.ctz
-     (local.get $y)
-    )
-    (i32.eqz
-     (local.get $x)
-    )
-   )
-  )
- )
- (func $ne0 (result i32)
-  (if
-   (call $ne0)
-   (nop)
-  )
-  (if
-   (call $ne0)
-   (nop)
-  )
-  (if
-   (i32.or
-    (call $ne0)
-    (call $ne0)
-   )
-   (nop)
-  )
-  (if
-   (i32.and
-    (i32.ne
-     (call $ne0)
-     (i32.const 0)
-    )
-    (i32.ne
-     (call $ne0)
-     (i32.const 0)
-    )
-   )
-   (nop)
-  )
-  (i32.const 1)
- )
- (func $recurse-bool
-  (if
-   (if (result i32)
-    (i32.const 1)
-    (call $ne0)
-    (call $ne1)
-   )
-   (nop)
-  )
-  (if
-   (block $block (result i32)
-    (nop)
-    (call $ne0)
-   )
-   (nop)
-  )
- )
- (func $ne1 (result i32)
-  (unreachable)
- )
- (func $load-off-2 (param $0 i32) (result i32)
-  (i32.store
-   (i32.const 6)
-   (local.get $0)
-  )
-  (i32.store
-   (i32.const 6)
-   (local.get $0)
-  )
-  (i32.store offset=2
-   (i32.add
-    (local.get $0)
-    (i32.const 5)
-   )
-   (local.get $0)
-  )
-  (i32.store offset=2
-   (i32.add
-    (local.get $0)
-    (i32.const 7)
-   )
-   (local.get $0)
-  )
-  (i32.store offset=2
-   (i32.add
-    (local.get $0)
-    (i32.const -11)
-   )
-   (local.get $0)
-  )
-  (i32.store offset=2
-   (i32.add
-    (local.get $0)
-    (i32.const -13)
-   )
-   (local.get $0)
-  )
-  (i32.store
-   (i32.const 4)
-   (local.get $0)
-  )
-  (i32.store offset=2
-   (i32.const -2)
-   (local.get $0)
-  )
-  (i32.store
-   (i32.const 25)
-   (local.get $0)
-  )
-  (i32.store offset=2
-   (i32.const -25)
-   (local.get $0)
-  )
-  (drop
-   (i32.load
-    (i32.const 8)
-   )
-  )
-  (drop
-   (i32.load
-    (i32.const 8)
-   )
-  )
-  (drop
-   (i32.load offset=2
-    (i32.add
-     (local.get $0)
-     (i32.const 6)
-    )
-   )
-  )
-  (drop
-   (i32.load
-    (i32.const 10)
-   )
-  )
-  (i32.load offset=2
-   (i32.add
-    (local.get $0)
-    (i32.const 10)
-   )
-  )
- )
- (func $sign-ext (param $0 i32) (param $1 i32)
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $0)
-     (i32.const 65535)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $0)
-     (i32.const 134217727)
-    )
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.const 100)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.const 107)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.and
-     (local.get $1)
-     (i32.const 255)
-    )
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $0)
-     (i32.const 65535)
-    )
-    (i32.and
-     (local.get $1)
-     (i32.const 65535)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.shr_s
-     (i32.shl
-      (local.get $0)
-      (i32.const 24)
-     )
-     (i32.const 23)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.shr_u
-     (i32.shl
-      (local.get $0)
-      (i32.const 24)
-     )
-     (i32.const 24)
-    )
-   )
-  )
-  (drop
-   (i32.lt_s
-    (i32.shr_s
-     (i32.shl
-      (local.get $0)
-      (i32.const 24)
-     )
-     (i32.const 24)
-    )
-    (i32.const 0)
-   )
-  )
- )
- (func $sign-ext-input (param $0 i32) (param $1 i32)
-  (drop
-   (i32.const 100)
-  )
-  (drop
-   (i32.const 127)
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.const 128)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (unreachable)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.const 1)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.const 127)
-    (i32.const 128)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.and
-      (i32.const 128)
-      (i32.const 129)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.xor
-    (i32.const 127)
-    (i32.const 126)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.xor
-      (i32.const 127)
-      (i32.const 128)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.or
-    (i32.const 127)
-    (i32.const 126)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.or
-      (i32.const 127)
-      (i32.const 128)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.const 32)
-     (i32.const 26)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shl
-    (i32.const 32)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.const 32)
-     (i32.const 27)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.shr_u
-      (i32.const 256)
-      (i32.const 1)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.const 256)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.const 128)
-    (i32.const 3)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.shr_u
-      (i32.const 256)
-      (i32.const 1)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.const 256)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.const 128)
-    (i32.const 3)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.const -1)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.and
-     (i32.const -1)
-     (i32.const 2147483647)
-    )
-    (i32.const 31)
-   )
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (f32.le
-    (f32.const -1)
-    (f32.const -1)
-   )
-  )
-  (drop
-   (i32.clz
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.clz
-      (i32.const 0)
-     )
-     (i32.const 26)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.clz
-      (i32.const 0)
-     )
-     (i32.const 27)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.wrap_i64
-    (i64.clz
-     (i64.const 0)
-    )
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.wrap_i64
-      (i64.clz
-       (i64.const 0)
-      )
-     )
-     (i32.const 25)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.wrap_i64
-      (i64.clz
-       (i64.const 0)
-      )
-     )
-     (i32.const 26)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.const -1)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.shr_u
-      (i32.wrap_i64
-       (i64.const -1)
-      )
-      (i32.const 24)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.wrap_i64
-     (i64.const -1)
-    )
-    (i32.const 25)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.shr_u
-      (i32.wrap_i64
-       (i64.extend_i32_s
-        (i32.const -1)
-       )
-      )
-      (i32.const 24)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.wrap_i64
-     (i64.extend_i32_s
-      (i32.const -1)
-     )
-    )
-    (i32.const 25)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.xor
-      (local.get $0)
-      (i32.le_u
-       (local.get $0)
-       (i32.const 2)
-      )
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
- )
- (func $linear-sums (param $0 i32) (param $1 i32)
-  (drop
-   (i32.add
-    (i32.shl
-     (local.get $0)
-     (i32.const 4)
-    )
-    (local.get $1)
-   )
-  )
-  (drop
-   (i32.add
-    (i32.add
-     (local.get $1)
-     (i32.shl
-      (local.get $0)
-      (i32.const 3)
-     )
-    )
-    (i32.const 12)
-   )
-  )
-  (drop
-   (i32.const 4)
-  )
-  (drop
-   (i32.const 18)
-  )
-  (drop
-   (i32.const 6)
-  )
-  (drop
-   (i32.const -4)
-  )
-  (drop
-   (i32.const 2)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 26)
-  )
-  (drop
-   (i32.const -20)
-  )
-  (drop
-   (i32.const 22)
-  )
-  (drop
-   (i32.add
-    (i32.shl
-     (i32.const 1)
-     (local.get $0)
-    )
-    (i32.const 14)
-   )
-  )
-  (drop
-   (i32.add
-    (i32.shl
-     (local.get $1)
-     (i32.const 3)
-    )
-    (i32.const -66)
-   )
-  )
-  (drop
-   (i32.const 44)
-  )
-  (drop
-   (i32.add
-    (i32.mul
-     (local.get $0)
-     (i32.const 10)
-    )
-    (i32.const 14)
-   )
-  )
-  (drop
-   (i32.add
-    (i32.shl
-     (local.get $0)
-     (i32.const 1)
-    )
-    (i32.const 34)
-   )
-  )
-  (drop
-   (local.get $0)
-  )
- )
- (func $almost-sign-ext (param $0 i32)
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.const 100)
-     (i32.const 25)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shl
-    (i32.const 50)
-    (i32.const 1)
-   )
-  )
- )
- (func $squaring (param $0 i32) (param $1 i32)
-  (drop
-   (i32.and
-    (local.get $0)
-    (i32.const 8)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $0)
-    (i32.const 11)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $0)
-    (i32.const 8)
-   )
-  )
-  (drop
-   (i32.or
-    (local.get $0)
-    (i32.const 203)
-   )
-  )
-  (drop
-   (i32.shl
-    (local.get $0)
-    (i32.const 19)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (local.get $0)
-    (i32.const 19)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (local.get $0)
-    (i32.const 19)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.shr_s
-     (local.get $0)
-     (i32.const 11)
-    )
-    (i32.const 8)
-   )
-  )
- )
- (func $sign-ext-ne (param $0 i32) (param $1 i32)
-  (drop
-   (i32.ne
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i32.ne
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i32.ne
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.const 107)
-   )
-  )
-  (drop
-   (i32.ne
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.const 111)
-   )
-  )
-  (drop
-   (i32.ne
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.and
-     (local.get $1)
-     (i32.const 255)
-    )
-   )
-  )
- )
- (func $sign-ext-eqz (param $0 i32) (param $1 i32)
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-   )
-  )
- )
- (func $sign-ext-boolean (param $0 i32) (param $1 i32)
-  (drop
-   (if (result i32)
-    (i32.and
-     (local.get $0)
-     (i32.const 255)
-    )
-    (i32.const 100)
-    (i32.const 200)
-   )
-  )
- )
- (func $add-sub-zero (param $0 i32) (param $1 i32)
-  (drop
-   (local.get $0)
-  )
-  (drop
-   (local.get $0)
-  )
- )
- (func $store-signext (param $0 i32)
-  (i32.store8
-   (i32.const 8)
-   (local.get $0)
-  )
-  (i32.store8
-   (i32.const 8)
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 25)
-    )
-    (i32.const 25)
-   )
-  )
-  (i32.store8
-   (i32.const 8)
-   (local.get $0)
-  )
-  (i32.store16
-   (i32.const 8)
-   (local.get $0)
-  )
-  (i32.store16
-   (i32.const 8)
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 17)
-    )
-    (i32.const 17)
-   )
-  )
-  (i32.store16
-   (i32.const 8)
-   (local.get $0)
-  )
-  (i32.store
-   (i32.const 8)
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 16)
-    )
-    (i32.const 16)
-   )
-  )
-  (i32.store
-   (i32.const 8)
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 8)
-    )
-    (i32.const 8)
-   )
-  )
- )
- (func $sign-ext-tee (param $0 i32) (param $1 i32)
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.tee $0
-      (i32.const 128)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (local.tee $0
-    (i32.const 127)
-   )
-  )
- )
- (func $sign-ext-load (param $0 i32) (param $1 i32)
-  (drop
-   (i32.load8_s
-    (i32.const 256)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.shr_u
-      (i32.load8_s
-       (i32.const 256)
-      )
-      (i32.const 1)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.load8_u
-     (i32.const 256)
-    )
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.load16_s
-    (i32.const 256)
-   )
-  )
-  (drop
-   (local.tee $1
-    (i32.load8_s
-     (i32.const 1)
-    )
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.tee $1
-      (i32.load8_u
-       (i32.const 1)
-      )
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.and
-    (local.tee $1
-     (i32.load8_s
-      (i32.const 1)
-     )
-    )
-    (i32.const 255)
-   )
-  )
-  (drop
-   (local.tee $1
-    (i32.load8_u
-     (i32.const 1)
-    )
-   )
-  )
- )
- (func $mask-bits (param $0 i32) (param $1 i32)
-  (drop
-   (local.tee $0
-    (i32.const 127)
-   )
-  )
-  (drop
-   (local.tee $0
-    (i32.const 128)
-   )
-  )
-  (drop
-   (i32.and
-    (local.tee $0
-     (i32.const 128)
-    )
-    (i32.const 254)
-   )
-  )
-  (drop
-   (i32.and
-    (local.tee $0
-     (i32.const 128)
-    )
-    (i32.const 1279)
-   )
-  )
-  (drop
-   (i32.and
-    (local.tee $0
-     (i32.const 128)
-    )
-    (i32.const 1290)
-   )
-  )
-  (drop
-   (local.tee $0
-    (i32.const 128)
-   )
-  )
-  (drop
-   (local.tee $0
-    (i32.const 128)
-   )
-  )
-  (drop
-   (i32.and
-    (local.tee $0
-     (i32.const 128)
-    )
-    (i32.const 127)
-   )
-  )
- )
- (func $local-info-zero-ext (param $0 i32) (param $1 i32)
-  (local $x i32)
-  (local $y i32)
-  (local $z i32)
-  (local $w i32)
-  (local.set $x
-   (i32.const 212)
-  )
-  (drop
-   (local.get $x)
-  )
-  (local.set $y
-   (i32.const 500)
-  )
-  (drop
-   (i32.and
-    (local.get $y)
-    (i32.const 255)
-   )
-  )
-  (local.set $0
-   (i32.const 212)
-  )
-  (drop
-   (i32.and
-    (local.get $0)
-    (i32.const 255)
-   )
-  )
-  (local.set $z
-   (i32.const 212)
-  )
-  (local.set $z
-   (i32.const 220)
-  )
-  (drop
-   (local.get $z)
-  )
-  (local.set $w
-   (i32.const 212)
-  )
-  (local.set $w
-   (i32.const 1000)
-  )
-  (drop
-   (i32.and
-    (local.get $w)
-    (i32.const 255)
-   )
-  )
- )
- (func $local-info-sign-ext-bitsize (param $0 i32) (param $1 i32)
-  (local $x i32)
-  (local $y i32)
-  (local $z i32)
-  (local $w i32)
-  (local.set $x
-   (i32.const 127)
-  )
-  (drop
-   (local.get $x)
-  )
-  (local.set $y
-   (i32.const 128)
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $y)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (local.set $0
-   (i32.const 127)
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (local.set $z
-   (i32.const 127)
-  )
-  (local.set $z
-   (i32.const 100)
-  )
-  (drop
-   (local.get $z)
-  )
-  (local.set $w
-   (i32.const 127)
-  )
-  (local.set $w
-   (i32.const 150)
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $w)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
- )
- (func $local-info-sign-ext-already-exted (param $0 i32) (param $1 i32)
-  (local $x i32)
-  (local $y i32)
-  (local $z i32)
-  (local $w i32)
-  (local.set $x
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (local.get $x)
-  )
-  (local.set $y
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 16)
-    )
-    (i32.const 16)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $y)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (local.set $0
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (local.set $z
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (local.set $z
-   (i32.shr_s
-    (i32.shl
-     (local.get $1)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (local.get $z)
-  )
-  (local.set $w
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (local.set $w
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 23)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $w)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $0)
-     (i32.const 24)
-    )
-    (i32.const 23)
-   )
-  )
- )
- (func $signed-loads-fill-the-bits (param $$e i32) (result i32)
-  (local $$0 i32)
-  (local $$conv i32)
-  (local.set $$0
-   (i32.load8_s
-    (i32.const 1024)
-   )
-  )
-  (local.set $$conv
-   (i32.and
-    (local.get $$0)
-    (i32.const 255)
-   )
-  )
-  (return
-   (i32.eq
-    (local.get $$e)
-    (local.get $$conv)
-   )
-  )
- )
- (func $local-info-sign-ext-already-exted-by-load (param $0 i32) (param $1 i32)
-  (local $x i32)
-  (local $y i32)
-  (local $z i32)
-  (local $w i32)
-  (local.set $x
-   (i32.load8_s
-    (i32.const 1024)
-   )
-  )
-  (drop
-   (local.get $x)
-  )
-  (local.set $y
-   (i32.load8_u
-    (i32.const 1024)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $y)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
-  (local.set $z
-   (i32.load16_s
-    (i32.const 1024)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (local.get $z)
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
- )
- (func $compare-load-s-sign-extend (param $0 i32) (param $1 i32)
-  (drop
-   (i32.eq
-    (i32.load8_u
-     (local.get $0)
-    )
-    (i32.and
-     (local.get $1)
-     (i32.const 255)
-    )
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.load8_u
-     (local.get $0)
-    )
-    (i32.and
-     (local.get $1)
-     (i32.const 255)
-    )
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.load8_u
-     (local.get $0)
-    )
-    (i32.shr_s
-     (i32.shl
-      (local.get $1)
-      (i32.const 24)
-     )
-     (i32.const 24)
-    )
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.load8_s
-     (local.get $0)
-    )
-    (i32.shr_s
-     (i32.shl
-      (local.get $1)
-      (i32.const 16)
-     )
-     (i32.const 16)
-    )
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.load8_u
-     (local.get $0)
-    )
-    (i32.shr_s
-     (i32.shl
-      (local.get $1)
-      (i32.const 24)
-     )
-     (i32.const 24)
-    )
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.load8_s
-     (local.get $0)
-    )
-    (i32.shr_s
-     (i32.shl
-      (local.get $1)
-      (i32.const 16)
-     )
-     (i32.const 16)
-    )
-   )
-  )
- )
- (func $unsign-diff-sizes (param $x i32) (param $y i32) (result i32)
-  (i32.ne
-   (i32.shr_s
-    (i32.shl
-     (call $unsign-diff-sizes
-      (i32.const -1)
-      (i32.const 5)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-   (i32.shr_s
-    (i32.shl
-     (call $unsign-diff-sizes
-      (i32.const 1)
-      (i32.const 2006)
-     )
-     (i32.const 16)
-    )
-    (i32.const 16)
-   )
-  )
- )
- (func $unsign-same-sizes (param $x i32) (param $y i32) (result i32)
-  (i32.ne
-   (i32.and
-    (call $unsign-same-sizes
-     (i32.const -1)
-     (i32.const 5)
-    )
-    (i32.const 255)
-   )
-   (i32.and
-    (call $unsign-same-sizes
-     (i32.const 1)
-     (i32.const 2006)
-    )
-    (i32.const 255)
-   )
-  )
- )
- (func $fuzz-almost-sign-ext
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.load16_u
-      (i32.const 2278)
-     )
-     (i32.const 17)
-    )
-    (i32.const 16)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.load16_u
-      (i32.const 2278)
-     )
-     (i32.const 17)
-    )
-    (i32.const 16)
-   )
-  )
- )
- (func $fuzz-comp-impossible (param $x i32)
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $x)
-     (i32.const 65535)
-    )
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $x)
-     (i32.const 255)
-    )
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $x)
-     (i32.const 255)
-    )
-    (i32.const 127)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $x)
-     (i32.const 255)
-    )
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $x)
-     (i32.const 255)
-    )
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $x)
-     (i32.const 255)
-    )
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.and
-     (local.get $x)
-     (i32.const 255)
-    )
-    (i32.const 252)
-   )
-  )
- )
- (func $if-parallel (param $0 i32) (param $1 i32)
-  (drop
-   (i32.add
-    (local.get $1)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (block (result i32)
-    (drop
-     (local.tee $0
-      (local.get $1)
-     )
-    )
-    (i32.add
-     (local.get $1)
-     (i32.const 1)
-    )
-   )
-  )
-  (drop
-   (block (result i32)
-    (i32.add
-     (local.get $1)
-     (unreachable)
-    )
-   )
-  )
-  (drop
-   (block (result i32)
-    (drop
-     (local.tee $0
-      (local.get $1)
-     )
-    )
-    (i32.add
-     (local.get $1)
-     (unreachable)
-    )
-   )
-  )
-  (drop
-   (if (result i32)
-    (unreachable)
-    (i32.add
-     (local.get $1)
-     (unreachable)
-    )
-    (i32.add
-     (local.get $1)
-     (unreachable)
-    )
-   )
-  )
- )
- (func $select-parallel (param $0 i32) (param $1 i32)
-  (drop
-   (i32.add
-    (local.get $1)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (select
-    (local.tee $0
-     (local.get $1)
-    )
-    (local.tee $0
-     (local.get $1)
-    )
-    (local.get $0)
-   )
-  )
-  (drop
-   (block (result i32)
-    (drop
-     (local.tee $0
-      (local.get $1)
-     )
-    )
-    (i32.add
-     (local.get $1)
-     (i32.const 1)
-    )
-   )
-  )
-  (drop
-   (select
-    (local.tee $0
-     (local.get $1)
-    )
-    (local.tee $0
-     (local.get $1)
-    )
-    (local.tee $0
-     (local.get $1)
-    )
-   )
-  )
-  (drop
-   (select
-    (local.tee $0
-     (local.get $1)
-    )
-    (local.tee $0
-     (local.get $1)
-    )
-    (unreachable)
-   )
-  )
- )
- (func $zero-shifts-is-not-sign-ext
-  (drop
-   (i32.eq
-    (i32.load16_s align=1
-     (i32.const 790656516)
-    )
-    (i32.const -5431187)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.shl
-     (i32.load16_s align=1
-      (i32.const 790656516)
-     )
-     (i32.const 1)
-    )
-    (i32.const -5431187)
-   )
-  )
- )
- (func $zero-ops (result i32)
-  (return
-   (i32.eq
-    (i32.load16_s align=1
-     (i32.const 790656516)
-    )
-    (i32.const -1337)
-   )
-  )
- )
- (func $sign-ext-1-and-ne (result i32)
-  (i32.ne
-   (i32.and
-    (call $sign-ext-1-and-ne)
-    (i32.const 2147483647)
-   )
-   (i32.const -2147483648)
-  )
- )
- (func $neg-shifts-and-255 (result i32)
-  (i32.and
-   (i32.const -99)
-   (i32.const 255)
-  )
- )
- (func $neg-shifts-and-255-b (result i32)
-  (i32.and
-   (i32.const -2349025)
-   (i32.const 255)
-  )
- )
- (func $shifts-square-overflow (param $x i32) (result i32)
-  (i32.shr_u
-   (i32.shr_u
-    (local.get $x)
-    (i32.const 31)
-   )
-   (i32.const 31)
-  )
- )
- (func $shifts-square-no-overflow-small (param $x i32) (result i32)
-  (i32.shr_u
-   (local.get $x)
-   (i32.const 9)
-  )
- )
- (func $shifts-square-overflow-64 (param $x i64) (result i64)
-  (i64.shr_u
-   (i64.shr_u
-    (local.get $x)
-    (i64.const 63)
-   )
-   (i64.const 63)
-  )
- )
- (func $shifts-square-no-overflow-small-64 (param $x i64) (result i64)
-  (i64.shr_u
-   (local.get $x)
-   (i64.const 9)
-  )
- )
- (func $shifts-square-unreachable (param $x i32) (result i32)
-  (i32.shr_u
-   (i32.shr_u
-    (unreachable)
-    (i32.const 1031)
-   )
-   (i32.const 4098)
-  )
- )
- (func $mix-shifts (result i32)
-  (i32.shr_u
-   (i32.shl
-    (i32.const 23)
-    (i32.const 3)
-   )
-   (i32.const 8)
-  )
- )
- (func $actually-no-shifts (result i32)
-  (i32.const 33)
- )
- (func $less-shifts-than-it-seems (param $x i32) (result i32)
-  (i32.const 4800)
- )
- (func $and-popcount32 (result i32)
-  (i32.and
-   (i32.popcnt
-    (i32.const -1)
-   )
-   (i32.const 31)
-  )
- )
- (func $and-popcount32-big (result i32)
-  (i32.popcnt
-   (i32.const -1)
-  )
- )
- (func $and-popcount64 (result i64)
-  (i64.and
-   (i64.popcnt
-    (i64.const -1)
-   )
-   (i64.const 63)
-  )
- )
- (func $and-popcount64-big (result i64)
-  (i64.and
-   (i64.popcnt
-    (i64.const -1)
-   )
-   (i64.const 127)
-  )
- )
- (func $and-popcount64-bigger (result i64)
-  (i64.and
-   (i64.popcnt
-    (i64.const -1)
-   )
-   (i64.const 255)
-  )
- )
- (func $optimizeAddedConstants-filters-through-nonzero (result i32)
-  (i32.add
-   (i32.shl
-    (i32.const -536870912)
-    (i32.wrap_i64
-     (i64.const 0)
-    )
-   )
-   (i32.const -31744)
-  )
- )
- (func $optimizeAddedConstants-filters-through-nonzero-b (result i32)
-  (i32.add
-   (i32.shl
-    (i32.const -536870912)
-    (i32.wrap_i64
-     (i64.const -1)
-    )
-   )
-   (i32.const -31744)
-  )
- )
- (func $return-proper-value-from-shift-left-by-zero (result i32)
-  (if (result i32)
-   (i32.add
-    (loop $label$0 (result i32)
-     (block $label$1
-      (br_if $label$1
-       (i32.load
-        (i32.const 0)
-       )
-      )
-     )
-     (i32.const -62)
-    )
-    (i32.const 40)
-   )
-   (i32.const 1)
-   (i32.const 0)
-  )
- )
- (func $de-morgan-2 (param $x i32) (param $y i32)
-  (drop
-   (i32.eqz
-    (i32.or
-     (local.get $x)
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.or
-    (i32.eqz
-     (local.get $x)
-    )
-    (i32.eqz
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.xor
-    (i32.eqz
-     (local.get $x)
-    )
-    (i32.eqz
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $y)
-    (i32.eqz
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (i32.eqz
-     (local.get $y)
-    )
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.and
-    (i32.eqz
-     (local.get $x)
-    )
-    (i32.wrap_i64
-     (i64.const 2)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (i32.eqz
-     (local.get $y)
-    )
-    (i32.wrap_i64
-     (i64.const 1)
-    )
-   )
-  )
- )
- (func $subzero1 (param $0 i32) (result i32)
-  (i32.sub
-   (i32.const 32)
-   (i32.clz
-    (local.get $0)
-   )
-  )
- )
- (func $subzero2 (param $0 i32) (result i32)
-  (i32.sub
-   (i32.const 32)
-   (i32.clz
-    (local.get $0)
-   )
-  )
- )
- (func $subzero3 (param $0 i32) (param $1 i32) (result i32)
-  (i32.sub
-   (local.get $1)
-   (i32.clz
-    (local.get $0)
-   )
-  )
- )
- (func $subzero4 (param $0 i32) (param $1 i32) (result i32)
-  (i32.sub
-   (local.get $0)
-   (i32.clz
-    (local.get $1)
-   )
-  )
- )
- (func $mul-32-power-2 (param $x i32) (result i32)
-  (drop
-   (call $mul-32-power-2
-    (i32.shl
-     (local.get $x)
-     (i32.const 2)
-    )
-   )
-  )
-  (drop
-   (call $mul-32-power-2
-    (i32.mul
-     (local.get $x)
-     (i32.const 5)
-    )
-   )
-  )
-  (drop
-   (call $mul-32-power-2
-    (local.get $x)
-   )
-  )
-  (drop
-   (call $mul-32-power-2
-    (i32.const 0)
-   )
-  )
-  (drop
-   (call $mul-32-power-2
-    (i32.mul
-     (call $mul-32-power-2
-      (i32.const 123)
-     )
-     (i32.const 0)
-    )
-   )
-  )
-  (drop
-   (call $mul-32-power-2
-    (i32.sub
-     (i32.const 0)
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (call $mul-32-power-2
-    (i32.shl
-     (local.get $x)
-     (i32.const 31)
-    )
-   )
-  )
-  (unreachable)
- )
- (func $mul-64-power-2 (param $x i64) (result i64)
-  (drop
-   (call $mul-64-power-2
-    (i64.shl
-     (local.get $x)
-     (i64.const 2)
-    )
-   )
-  )
-  (drop
-   (call $mul-64-power-2
-    (i64.mul
-     (local.get $x)
-     (i64.const 5)
-    )
-   )
-  )
-  (drop
-   (call $mul-64-power-2
-    (local.get $x)
-   )
-  )
-  (drop
-   (call $mul-64-power-2
-    (i64.const 0)
-   )
-  )
-  (drop
-   (call $mul-64-power-2
-    (i64.mul
-     (call $mul-64-power-2
-      (i64.const 123)
-     )
-     (i64.const 0)
-    )
-   )
-  )
-  (drop
-   (call $mul-64-power-2
-    (i64.sub
-     (i64.const 0)
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (call $mul-64-power-2
-    (i64.shl
-     (local.get $x)
-     (i64.const 63)
-    )
-   )
-  )
-  (unreachable)
- )
- (func $div-32-power-2 (param $x i32) (result i32)
-  (drop
-   (call $div-32-power-2
-    (i32.shr_u
-     (local.get $x)
-     (i32.const 2)
-    )
-   )
-  )
-  (drop
-   (call $div-32-power-2
-    (i32.div_u
-     (local.get $x)
-     (i32.const 5)
-    )
-   )
-  )
-  (drop
-   (call $div-32-power-2
-    (local.get $x)
-   )
-  )
-  (drop
-   (call $div-32-power-2
-    (i32.div_u
-     (local.get $x)
-     (i32.const 0)
-    )
-   )
-  )
-  (drop
-   (call $div-32-power-2
-    (i32.div_u
-     (call $div-32-power-2
-      (i32.const 123)
-     )
-     (i32.const 0)
-    )
-   )
-  )
-  (drop
-   (call $div-32-power-2
-    (i32.eq
-     (local.get $x)
-     (i32.const -1)
-    )
-   )
-  )
-  (drop
-   (call $div-32-power-2
-    (i32.shr_u
-     (local.get $x)
-     (i32.const 31)
-    )
-   )
-  )
-  (unreachable)
- )
- (func $urem-32-power-2 (param $x i32) (result i32)
-  (drop
-   (call $urem-32-power-2
-    (i32.and
-     (local.get $x)
-     (i32.const 3)
-    )
-   )
-  )
-  (drop
-   (call $urem-32-power-2
-    (i32.rem_u
-     (local.get $x)
-     (i32.const 5)
-    )
-   )
-  )
-  (drop
-   (call $urem-32-power-2
-    (i32.const 0)
-   )
-  )
-  (drop
-   (call $urem-32-power-2
-    (i32.rem_u
-     (local.get $x)
-     (i32.const 0)
-    )
-   )
-  )
-  (drop
-   (call $urem-32-power-2
-    (i32.rem_u
-     (local.get $x)
-     (i32.const -1)
-    )
-   )
-  )
-  (drop
-   (call $urem-32-power-2
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-   )
-  )
-  (drop
-   (call $urem-32-power-2
-    (i32.const 0)
-   )
-  )
-  (unreachable)
- )
- (func $srem-by-const (param $x i32) (param $y i64)
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i64.const 0)
-  )
-  (drop
-   (i32.rem_s
-    (local.get $x)
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i64.rem_s
-    (local.get $y)
-    (i64.const -9223372036854775808)
-   )
-  )
- )
- (func $srem-by-pot-eq-ne-zero (param $x i32) (param $y i64)
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $x)
-     (i32.const 3)
-    )
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.and
-     (local.get $y)
-     (i64.const 3)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $x)
-     (i32.const 3)
-    )
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.and
-     (local.get $y)
-     (i64.const 3)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $x)
-     (i32.const 3)
-    )
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.and
-     (local.get $y)
-     (i64.const 1)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $x)
-     (i32.const 3)
-    )
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.and
-     (local.get $y)
-     (i64.const 3)
-    )
-   )
-  )
-  (drop
-   (i32.ne
-    (i32.and
-     (local.get $x)
-     (i32.const 1)
-    )
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.wrap_i64
-    (i64.and
-     (local.get $y)
-     (i64.const 1)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-   )
-  )
-  (drop
-   (i32.ne
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.and
-     (local.get $y)
-     (i64.const 9223372036854775807)
-    )
-   )
-  )
-  (drop
-   (i64.ne
-    (i64.and
-     (local.get $y)
-     (i64.const 9223372036854775807)
-    )
-    (i64.const 0)
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.rem_s
-     (local.get $x)
-     (i32.const 3)
-    )
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.rem_s
-     (local.get $y)
-     (i64.const 3)
-    )
-   )
-  )
- )
- (func $orZero (param $0 i32) (result i32)
-  (local.get $0)
- )
- (func $andZero (param $0 i32) (result i32)
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.and
-    (call $andZero
-     (i32.const 1234)
-    )
-    (i32.const 0)
-   )
-  )
-  (unreachable)
- )
- (func $abstract-additions (param $x32 i32) (param $x64 i64) (param $y32 f32) (param $y64 f64)
-  (drop
-   (local.get $x32)
-  )
-  (drop
-   (local.get $x32)
-  )
-  (drop
-   (local.get $x32)
-  )
-  (drop
-   (local.get $x32)
-  )
-  (drop
-   (local.get $x64)
-  )
-  (drop
-   (local.get $x64)
-  )
-  (drop
-   (local.get $x64)
-  )
-  (drop
-   (local.get $x64)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i64.const 0)
-  )
-  (drop
-   (f32.mul
-    (local.get $y32)
-    (f32.const 0)
-   )
-  )
-  (drop
-   (f64.mul
-    (local.get $y64)
-    (f64.const 0)
-   )
-  )
-  (drop
-   (local.get $x32)
-  )
-  (drop
-   (local.get $x64)
-  )
-  (drop
-   (f32.mul
-    (local.get $y32)
-    (f32.const 1)
-   )
-  )
-  (drop
-   (f64.mul
-    (local.get $y64)
-    (f64.const 1)
-   )
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i64.const 0)
-  )
-  (drop
-   (i32.and
-    (unreachable)
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i64.and
-    (unreachable)
-    (i64.const 0)
-   )
-  )
-  (drop
-   (local.get $x32)
-  )
-  (drop
-   (local.get $x32)
-  )
-  (drop
-   (local.get $x64)
-  )
-  (drop
-   (local.get $x64)
-  )
-  (drop
-   (f32.div
-    (local.get $y32)
-    (f32.const 1)
-   )
-  )
-  (drop
-   (f64.div
-    (local.get $y64)
-    (f64.const 1)
-   )
-  )
-  (drop
-   (f32.div
-    (local.get $y32)
-    (f32.const 1.2000000476837158)
-   )
-  )
-  (drop
-   (i32.sub
-    (i32.const 0)
-    (local.get $x32)
-   )
-  )
-  (drop
-   (i64.sub
-    (i64.const 0)
-    (local.get $x64)
-   )
-  )
-  (drop
-   (f32.mul
-    (local.get $y32)
-    (f32.const -1)
-   )
-  )
-  (drop
-   (f64.mul
-    (local.get $y64)
-    (f64.const -1)
-   )
-  )
-  (drop
-   (i32.eq
-    (local.get $x32)
-    (i32.const 10)
-   )
-  )
-  (drop
-   (i32.le_u
-    (i32.add
-     (local.get $x32)
-     (i32.const 10)
-    )
-    (i32.const 20)
-   )
-  )
-  (drop
-   (i32.eq
-    (local.get $x32)
-    (i32.const 30)
-   )
-  )
-  (drop
-   (i64.eq
-    (local.get $x64)
-    (i64.const 10)
-   )
-  )
-  (drop
-   (i32.eq
-    (local.get $x32)
-    (i32.const 10)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.add
-     (local.get $x32)
-     (i32.const 10)
-    )
-    (local.get $x32)
-   )
-  )
-  (drop
-   (i32.eq
-    (local.get $x32)
-    (i32.const 30)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.sub
-     (local.get $x32)
-     (i32.const 30)
-    )
-    (local.get $x32)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.sub
-     (local.get $x32)
-     (i32.const 30)
-    )
-    (local.get $x32)
-   )
-  )
-  (drop
-   (i32.eq
-    (i32.sub
-     (local.get $x32)
-     (i32.const 10)
-    )
-    (local.get $x32)
-   )
-  )
-  (drop
-   (i64.le_s
-    (i64.sub
-     (local.get $x64)
-     (i64.const 288230376151711744)
-    )
-    (i64.const 9223372036854775807)
-   )
-  )
- )
- (func $negatives-are-sometimes-better (param $x i32) (param $y i64) (param $z f32)
-  (drop
-   (i32.sub
-    (local.get $x)
-    (i32.const -64)
-   )
-  )
-  (drop
-   (i32.add
-    (local.get $x)
-    (i32.const -64)
-   )
-  )
-  (drop
-   (i32.sub
-    (local.get $x)
-    (i32.const -8192)
-   )
-  )
-  (drop
-   (i32.sub
-    (local.get $x)
-    (i32.const -1048576)
-   )
-  )
-  (drop
-   (i32.sub
-    (local.get $x)
-    (i32.const -134217728)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -64)
-   )
-  )
-  (drop
-   (i64.add
-    (local.get $y)
-    (i64.const -64)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -8192)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -1048576)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -134217728)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -17179869184)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -2199023255552)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -281474976710656)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -36028797018963968)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -4611686018427387904)
-   )
-  )
-  (drop
-   (f32.add
-    (local.get $z)
-    (f32.const 64)
-   )
-  )
- )
- (func $shift-a-zero (param $x i32) (param $y i64) (param $z f32)
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i64.const 0)
-  )
-  (drop
-   (i32.shl
-    (i32.const 0)
-    (unreachable)
-   )
-  )
- )
- (func $identical-siblings (param $x i32) (param $y i64) (param $z f64) (param $xx i32)
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i64.const 0)
-  )
-  (drop
-   (f64.sub
-    (local.get $z)
-    (local.get $z)
-   )
-  )
-  (drop
-   (i32.sub
-    (local.get $x)
-    (local.get $xx)
-   )
-  )
-  (drop
-   (i32.sub
-    (unreachable)
-    (unreachable)
-   )
-  )
-  (drop
-   (i32.add
-    (local.get $x)
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i64.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 1)
-  )
- )
- (func $all_ones (param $x i32) (param $y i64)
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (i32.const -1)
-  )
-  (drop
-   (i32.or
-    (local.tee $x
-     (i32.const 1337)
-    )
-    (i32.const -1)
-   )
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (i64.const -1)
-  )
- )
- (func $xor (param $x i32) (param $y i64)
-  (drop
-   (local.get $x)
-  )
- )
- (func $select-on-const (param $x i32) (param $y i64)
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (i32.const 3)
-  )
-  (drop
-   (local.tee $x
-    (i32.const 5)
-   )
-  )
-  (drop
-   (block (result i32)
-    (drop
-     (local.tee $x
-      (i32.const 6)
-     )
-    )
-    (i32.const 7)
-   )
-  )
-  (drop
-   (select
-    (i32.const 4)
-    (local.tee $x
-     (i32.const 5)
-    )
-    (i32.const 1)
-   )
-  )
-  (drop
-   (local.tee $x
-    (i32.const 6)
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.eqz
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.ge_s
-    (local.get $x)
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.lt_s
-    (local.get $x)
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.lt_s
-    (local.get $x)
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.gt_s
-    (local.get $x)
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.le_s
-    (local.get $x)
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.ge_s
-    (local.get $x)
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i32.eqz
-     (i32.eqz
-      (local.get $x)
-     )
-    )
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i32.eqz
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i64.eqz
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i32.eqz
-     (i64.eqz
-      (local.get $y)
-     )
-    )
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i64.ge_s
-     (local.get $y)
-     (i64.const 0)
-    )
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i64.lt_s
-     (local.get $y)
-     (i64.const 0)
-    )
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i64.lt_s
-     (local.get $y)
-     (i64.const 0)
-    )
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i64.ge_s
-     (local.get $y)
-     (i64.const 0)
-    )
-   )
-  )
-  (drop
-   (select
-    (i32.const 0)
-    (local.get $x)
-    (i32.const 0)
-   )
-  )
-  (drop
-   (select
-    (i32.const 2)
-    (local.get $x)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (select
-    (local.get $x)
-    (i32.const 2)
-    (local.get $x)
-   )
-  )
-  (drop
-   (select
-    (local.get $y)
-    (i64.const 0)
-    (i64.eqz
-     (i64.const 0)
-    )
-   )
-  )
-  (drop
-   (select
-    (local.get $y)
-    (i64.const 2)
-    (i64.eqz
-     (i64.const 2)
-    )
-   )
-  )
- )
- (func $optimize-boolean (param $x i32) (param $y i64)
-  (drop
-   (select
-    (i32.const 1)
-    (i32.const 2)
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.and
-     (local.get $x)
-     (i32.const 1)
-    )
-   )
-  )
-  (drop
-   (i32.wrap_i64
-    (i64.shr_u
-     (local.get $y)
-     (i64.const 63)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.shr_u
-     (local.get $x)
-     (i32.const 31)
-    )
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.shr_u
-     (local.get $y)
-     (i64.const 63)
-    )
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.shr_u
-     (local.get $y)
-     (i64.const 63)
-    )
-   )
-  )
-  (drop
-   (i64.eqz
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.eqz
-    (i32.wrap_i64
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.wrap_i64
-    (i64.and
-     (local.get $y)
-     (i64.const 1)
-    )
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.and
-     (local.get $y)
-     (i64.const 1)
-    )
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i64.and
-    (local.get $y)
-    (i64.const 1)
-   )
-  )
-  (drop
-   (i64.const 1)
-  )
- )
- (func $optimize-bitwise-oprations (param $x i32) (param $y i32) (param $z i64) (param $w i64)
-  (drop
-   (i32.rotl
-    (i32.const -2)
-    (local.get $x)
-   )
-  )
-  (drop
-   (i64.rotl
-    (i64.const -2)
-    (local.get $z)
-   )
-  )
- )
- (func $getFallthrough
-  (local $x0 i32)
-  (local $x1 i32)
-  (local $x2 i32)
-  (local $x3 i32)
-  (local $x4 i32)
-  (local $x5 i32)
-  (local $x6 i32)
-  (local $x7 i32)
-  (local.set $x0
-   (i32.const 1)
-  )
-  (drop
-   (local.get $x0)
-  )
-  (local.set $x1
-   (local.tee $x2
-    (i32.const 1)
-   )
-  )
-  (drop
-   (local.get $x1)
-  )
-  (local.set $x3
-   (loop $loop-in (result i32)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (local.get $x3)
-  )
-  (local.set $x4
-   (if (result i32)
-    (i32.const 1)
-    (i32.const 2)
-    (i32.const 3)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x4)
-    (i32.const 7)
-   )
-  )
-  (local.set $x5
-   (if (result i32)
-    (i32.const 1)
-    (unreachable)
-    (i32.const 3)
-   )
-  )
-  (drop
-   (local.get $x5)
-  )
-  (local.set $x6
-   (if (result i32)
-    (i32.const 1)
-    (i32.const 3)
-    (unreachable)
-   )
-  )
-  (drop
-   (local.get $x6)
-  )
-  (drop
-   (block $out (result i32)
-    (local.set $x7
-     (br_if $out
-      (i32.const 1)
-      (i32.const 1)
-     )
-    )
-    (drop
-     (local.get $x7)
-    )
-    (unreachable)
-   )
-  )
- )
- (func $tee-with-unreachable-value (result f64)
-  (local $var$0 i32)
-  (block $label$1 (result f64)
-   (local.tee $var$0
-    (br_if $label$1
-     (f64.const 1)
-     (unreachable)
-    )
-   )
-  )
- )
- (func $add-sub-zero-reorder-1 (param $temp i32) (result i32)
-  (i32.add
-   (i32.add
-    (i32.sub
-     (i32.const 0)
-     (local.get $temp)
-    )
-    (local.tee $temp
-     (i32.const 1)
-    )
-   )
-   (i32.const 2)
-  )
- )
- (func $add-sub-zero-reorder-2 (param $temp i32) (result i32)
-  (i32.add
-   (i32.sub
-    (local.tee $temp
-     (i32.const 1)
-    )
-    (local.get $temp)
-   )
-   (i32.const 2)
-  )
- )
- (func $const-float-zero (param $fx f32) (param $fy f64)
-  (drop
-   (f32.sub
-    (local.get $fx)
-    (f32.const 0)
-   )
-  )
-  (drop
-   (f64.sub
-    (local.get $fy)
-    (f64.const 0)
-   )
-  )
-  (drop
-   (f32.add
-    (local.get $fx)
-    (f32.const -0)
-   )
-  )
-  (drop
-   (f64.add
-    (local.get $fy)
-    (f64.const -0)
-   )
-  )
-  (drop
-   (f32.add
-    (local.get $fx)
-    (f32.const 0)
-   )
-  )
-  (drop
-   (f64.add
-    (local.get $fy)
-    (f64.const 0)
-   )
-  )
-  (drop
-   (f32.sub
-    (f32.const 0)
-    (local.get $fx)
-   )
-  )
-  (drop
-   (f64.sub
-    (f64.const 0)
-    (local.get $fy)
-   )
-  )
-  (drop
-   (f32.add
-    (local.get $fx)
-    (f32.const 0)
-   )
-  )
-  (drop
-   (f64.add
-    (local.get $fy)
-    (f64.const 0)
-   )
-  )
-  (drop
-   (f32.sub
-    (f32.const -nan:0x34546d)
-    (f32.const 0)
-   )
-  )
- )
- (func $rhs-is-neg-one (param $x i32) (param $y i64) (param $fx f32) (param $fy f64)
-  (drop
-   (i32.sub
-    (local.get $x)
-    (i32.const -1)
-   )
-  )
-  (drop
-   (i64.sub
-    (local.get $y)
-    (i64.const -1)
-   )
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.const 0)
-  )
-  (drop
-   (i32.gt_s
-    (local.get $x)
-    (i32.const -1)
-   )
-  )
-  (drop
-   (i64.gt_s
-    (local.get $y)
-    (i64.const -1)
-   )
-  )
-  (drop
-   (i64.extend_i32_s
-    (i32.const 0)
-   )
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.const 1)
-  )
-  (drop
-   (i32.le_s
-    (local.get $x)
-    (i32.const -1)
-   )
-  )
-  (drop
-   (i64.le_s
-    (local.get $y)
-    (i64.const -1)
-   )
-  )
-  (drop
-   (i32.sub
-    (i32.const 0)
-    (local.get $x)
-   )
-  )
-  (drop
-   (i64.sub
-    (i64.const 0)
-    (local.get $y)
-   )
-  )
-  (drop
-   (f32.mul
-    (local.get $fx)
-    (f32.const -1)
-   )
-  )
-  (drop
-   (f64.mul
-    (local.get $fy)
-    (f64.const -1)
-   )
-  )
-  (drop
-   (i32.eq
-    (local.get $x)
-    (i32.const -1)
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i64.eq
-     (local.get $y)
-     (i64.const -1)
-    )
-   )
-  )
- )
- (func $rhs-is-neg-const (param $x i32) (param $y i64)
-  (drop
-   (i32.ge_u
-    (local.get $x)
-    (i32.const -2)
-   )
-  )
-  (drop
-   (i32.eq
-    (local.get $x)
-    (i32.const -1)
-   )
-  )
-  (drop
-   (i32.ge_u
-    (local.get $x)
-    (i32.const -2147483647)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (local.get $x)
-    (i32.const 31)
-   )
-  )
-  (drop
-   (i64.extend_i32_u
-    (i64.eq
-     (local.get $y)
-     (i64.const -1)
-    )
-   )
-  )
-  (drop
-   (i64.shr_u
-    (local.get $y)
-    (i64.const 63)
-   )
-  )
- )
- (func $pre-combine-or (param $x i32) (param $y i32)
-  (drop
-   (i32.ge_s
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.ge_s
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.or
-    (i32.eq
-     (local.get $x)
-     (i32.const 1)
-    )
-    (i32.gt_s
-     (local.get $x)
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.or
-    (i32.eq
-     (local.get $x)
-     (local.get $y)
-    )
-    (i32.gt_s
-     (local.get $x)
-     (i32.const 1)
-    )
-   )
-  )
-  (drop
-   (i32.or
-    (i32.gt_s
-     (call $ne0)
-     (local.get $y)
-    )
-    (i32.eq
-     (call $ne0)
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.or
-    (i32.gt_s
-     (local.get $y)
-     (call $ne0)
-    )
-    (i32.eq
-     (call $ne0)
-     (local.get $y)
-    )
-   )
-  )
- )
- (func $combine-or (param $x i32) (param $y i32)
-  (drop
-   (i32.ge_s
-    (local.get $x)
-    (local.get $y)
-   )
-  )
- )
- (func $select-into-arms (param $x i32) (param $y i32)
-  (if
-   (select
-    (local.get $x)
-    (local.get $y)
-    (local.get $y)
-   )
-   (unreachable)
-  )
- )
- (func $if-arms-subtype-fold (result anyref)
-  (ref.null extern)
- )
- (func $if-arms-subtype-nofold (result anyref)
-  (if (result anyref)
-   (i32.const 0)
-   (ref.null extern)
-   (ref.null func)
-  )
- )
- (func $optimize-boolean-context (param $x i32) (param $y i32)
-  (if
-   (local.get $x)
-   (unreachable)
-  )
-  (drop
-   (select
-    (local.get $x)
-    (local.get $y)
-    (local.get $x)
-   )
-  )
- )
- (func $unsigned-context (param $x i32) (param $y i64)
-  (drop
-   (i32.div_u
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-    (i32.const 3)
-   )
-  )
-  (drop
-   (i32.div_s
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-    (i32.const -3)
-   )
-  )
-  (drop
-   (i32.div_s
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-    (i32.const -2147483648)
-   )
-  )
-  (drop
-   (i64.shr_u
-    (i64.and
-     (local.get $y)
-     (i64.const 9223372036854775807)
-    )
-    (i64.const 1)
-   )
-  )
-  (drop
-   (i64.div_s
-    (i64.and
-     (local.get $y)
-     (i64.const 9223372036854775807)
-    )
-    (i64.const -1)
-   )
-  )
-  (drop
-   (i32.rem_u
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-    (i32.const 3)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-    (i32.const 7)
-   )
-  )
-  (drop
-   (i32.ge_u
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-    (i32.const 7)
-   )
-  )
-  (drop
-   (i32.ge_s
-    (i32.and
-     (local.get $x)
-     (i32.const 2147483647)
-    )
-    (i32.const -7)
-   )
-  )
- )
- (func $duplicate-elimination (param $x i32) (param $y i32) (param $z i32) (param $w f64)
-  (drop
-   (f64.abs
-    (local.get $w)
-   )
-  )
-  (drop
-   (f64.ceil
-    (local.get $w)
-   )
-  )
-  (drop
-   (f64.floor
-    (local.get $w)
-   )
-  )
-  (drop
-   (f64.trunc
-    (local.get $w)
-   )
-  )
-  (drop
-   (f64.nearest
-    (local.get $w)
-   )
-  )
-  (drop
-   (f64.nearest
-    (f64.trunc
-     (local.get $w)
-    )
-   )
-  )
-  (drop
-   (f64.trunc
-    (f64.nearest
-     (local.get $w)
-    )
-   )
-  )
-  (drop
-   (local.get $w)
-  )
-  (drop
-   (f64.neg
-    (local.get $w)
-   )
-  )
-  (drop
-   (local.get $w)
-  )
-  (drop
-   (i32.eqz
-    (i32.eqz
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (i32.eqz
-    (local.get $x)
-   )
-  )
-  (drop
-   (i64.eqz
-    (i64.const 1)
-   )
-  )
-  (drop
-   (i32.ne
-    (local.get $x)
-    (i32.const 2)
-   )
-  )
-  (drop
-   (i32.extend8_s
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.extend16_s
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (i32.const 1)
-   )
-  )
-  (drop
-   (i32.rem_s
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.rem_u
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (i32.sub
-    (local.get $y)
-    (i32.sub
-     (local.get $x)
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (local.get $y)
-  )
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.and
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.or
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.or
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.or
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.or
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.or
-    (local.get $z)
-    (i32.or
-     (local.get $x)
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.or
-    (local.get $y)
-    (i32.or
-     (local.get $x)
-     (local.get $z)
-    )
-   )
-  )
-  (drop
-   (i32.or
-    (call $ne0)
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.or
-    (i32.or
-     (call $ne0)
-     (local.get $x)
-    )
-    (call $ne0)
-   )
-  )
-  (drop
-   (i32.or
-    (call $ne0)
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.or
-    (call $ne0)
-    (i32.or
-     (call $ne0)
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (i32.rem_s
-    (i32.rem_s
-     (local.get $y)
-     (local.get $x)
-    )
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.rem_u
-    (local.get $y)
-    (i32.rem_u
-     (local.get $x)
-     (local.get $y)
-    )
-   )
-  )
-  (drop
-   (i32.or
-    (local.get $x)
-    (i32.or
-     (local.tee $x
-      (i32.const 1)
-     )
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (i32.or
-    (i32.or
-     (local.get $x)
-     (local.tee $x
-      (i32.const 1)
-     )
-    )
-    (local.get $x)
-   )
-  )
-  (drop
-   (i32.xor
-    (local.get $x)
-    (i32.xor
-     (local.tee $x
-      (i32.const 1)
-     )
-     (local.get $x)
-    )
-   )
-  )
-  (drop
-   (i32.xor
-    (i32.xor
-     (local.get $x)
-     (local.tee $x
-      (i32.const 1)
-     )
-    )
-    (local.get $x)
-   )
-  )
- )
- (func $optimize-shifts (param $x i32) (param $y i32) (param $z i64) (param $w i64)
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (local.get $x)
-  )
-  (drop
-   (local.get $z)
-  )
-  (drop
-   (local.get $z)
-  )
-  (drop
-   (local.get $z)
-  )
-  (drop
-   (local.get $z)
-  )
-  (drop
-   (local.get $z)
-  )
-  (drop
-   (i32.shl
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.shl
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.shr_s
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i32.shr_u
-    (local.get $x)
-    (local.get $y)
-   )
-  )
-  (drop
-   (i64.shl
-    (local.get $z)
-    (local.get $w)
-   )
-  )
-  (drop
-   (i64.shl
-    (local.get $z)
-    (local.get $w)
-   )
-  )
-  (drop
-   (i64.shr_s
-    (local.get $z)
-    (local.get $w)
-   )
-  )
-  (drop
-   (i64.shr_u
-    (local.get $z)
-    (local.get $w)
-   )
-  )
-  (drop
-   (i32.shl
-    (local.get $x)
-    (i32.and
-     (local.get $y)
-     (i32.const 32)
-    )
-   )
-  )
-  (drop
-   (i64.shr_u
-    (local.get $z)
-    (i64.and
-     (local.get $w)
-     (i64.const 31)
-    )
-   )
-  )
- )
- (func $optimize-bulk-memory-copy (param $dst i32) (param $src i32) (param $sz i32)
-  (memory.copy
-   (local.get $dst)
-   (local.get $dst)
-   (local.get $sz)
-  )
-  (memory.copy
-   (local.get $dst)
-   (local.get $src)
-   (i32.const 0)
-  )
-  (i32.store8
-   (local.get $dst)
-   (i32.load8_u
-    (local.get $src)
-   )
-  )
-  (i32.store16 align=1
-   (local.get $dst)
-   (i32.load16_u align=1
-    (local.get $src)
-   )
-  )
-  (memory.copy
-   (local.get $dst)
-   (local.get $src)
-   (i32.const 3)
-  )
-  (i32.store align=1
-   (local.get $dst)
-   (i32.load align=1
-    (local.get $src)
-   )
-  )
-  (memory.copy
-   (local.get $dst)
-   (local.get $src)
-   (i32.const 5)
-  )
-  (memory.copy
-   (local.get $dst)
-   (local.get $src)
-   (i32.const 6)
-  )
-  (memory.copy
-   (local.get $dst)
-   (local.get $src)
-   (i32.const 7)
-  )
-  (i64.store align=1
-   (local.get $dst)
-   (i64.load align=1
-    (local.get $src)
-   )
-  )
-  (v128.store align=1
-   (local.get $dst)
-   (v128.load align=1
-    (local.get $src)
-   )
-  )
-  (memory.copy
-   (local.get $dst)
-   (local.get $src)
-   (local.get $sz)
-  )
-  (memory.copy
-   (i32.const 0)
-   (i32.const 0)
-   (i32.load
-    (i32.const 3)
-   )
-  )
- )
-)
-(module
- (type $none_=>_none (func))
- (import "env" "memory" (memory $0 (shared 256 256)))
- (func $x
-  (drop
-   (i32.shr_s
-    (i32.shl
-     (i32.atomic.load8_u
-      (i32.const 100)
-     )
-     (i32.const 24)
-    )
-    (i32.const 24)
-   )
-  )
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $i32_i64_=>_none (func (param i32 i64)))
+ (type $none_=>_none (func))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_=>_none (func (param i32)))
+ (type $i32_i32_i64_i64_=>_none (func (param i32 i32 i64 i64)))
+ (type $i32_i64_f32_f64_=>_none (func (param i32 i64 f32 f64)))
+ (type $none_=>_i64 (func (result i64)))
+ (type $i64_=>_i64 (func (param i64) (result i64)))
+ (type $i32_i64_f32_=>_none (func (param i32 i64 f32)))
+ (type $f32_=>_none (func (param f32)))
+ (type $f64_=>_none (func (param f64)))
+ (type $i32_i32_i32_f64_=>_none (func (param i32 i32 i32 f64)))
+ (type $i32_i32_f64_f64_=>_none (func (param i32 i32 f64 f64)))
+ (type $i32_i64_f64_i32_=>_none (func (param i32 i64 f64 i32)))
+ (type $f32_f64_=>_none (func (param f32 f64)))
+ (type $f64_f32_=>_none (func (param f64 f32)))
+ (type $f64_f64_f32_f32_=>_none (func (param f64 f64 f32 f32)))
+ (type $none_=>_f64 (func (result f64)))
+ (memory $0 0)
+ (export "load-off-2" (func $load-off-2))
+ (func $f (param $i1 i32) (param $i2 i64)
+  (drop
+   (i32.and
+    (local.get $i1)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.or
+    (local.get $i1)
+    (i32.const 3)
+   )
+  )
+  (drop
+   (i32.xor
+    (local.get $i1)
+    (i32.const 5)
+   )
+  )
+  (drop
+   (i32.mul
+    (local.get $i1)
+    (i32.const -10)
+   )
+  )
+  (drop
+   (i32.mul
+    (local.get $i1)
+    (i32.const -133169153)
+   )
+  )
+  (if
+   (i32.eqz
+    (local.get $i1)
+   )
+   (drop
+    (i32.const 10)
+   )
+  )
+  (if
+   (local.get $i1)
+   (drop
+    (i32.const 12)
+   )
+   (drop
+    (i32.const 11)
+   )
+  )
+  (if
+   (i64.eqz
+    (local.get $i2)
+   )
+   (drop
+    (i32.const 11)
+   )
+   (drop
+    (i32.const 12)
+   )
+  )
+  (drop
+   (i32.le_u
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.lt_u
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.ge_u
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.gt_u
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.le_u
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.lt_u
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.ge_u
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.gt_u
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.eqz
+    (f32.gt
+     (f32.const 1)
+     (f32.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (f32.ge
+     (f32.const 1)
+     (f32.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (f32.lt
+     (f32.const 1)
+     (f32.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (f32.le
+     (f32.const 1)
+     (f32.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (f64.gt
+     (f64.const 1)
+     (f64.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (f64.ge
+     (f64.const 1)
+     (f64.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (f64.lt
+     (f64.const 1)
+     (f64.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (f64.le
+     (f64.const 1)
+     (f64.const 2)
+    )
+   )
+  )
+  (drop
+   (f32.ne
+    (f32.const 1)
+    (f32.const 2)
+   )
+  )
+  (drop
+   (f32.eq
+    (f32.const 1)
+    (f32.const 2)
+   )
+  )
+  (drop
+   (f64.ne
+    (f64.const 1)
+    (f64.const 2)
+   )
+  )
+  (drop
+   (f64.eq
+    (f64.const 1)
+    (f64.const 2)
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.const 100)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.const 0)
+    (i32.const 100)
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.eq
+    (i64.const 0)
+    (i64.const 100)
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.const 0)
+   )
+  )
+  (if
+   (i32.const 123)
+   (nop)
+  )
+  (drop
+   (select
+    (i32.const 102)
+    (i32.const 101)
+    (local.get $i1)
+   )
+  )
+  (drop
+   (select
+    (local.tee $i1
+     (i32.const 103)
+    )
+    (local.tee $i1
+     (i32.const 104)
+    )
+    (i32.eqz
+     (local.get $i1)
+    )
+   )
+  )
+  (drop
+   (i32.const 0)
+  )
+ )
+ (func $load-store
+  (drop
+   (i32.load8_u
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.load8_u
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.load8_s
+     (i32.const 2)
+    )
+    (i32.const 254)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.load8_u
+     (i32.const 3)
+    )
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load16_u
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.load16_u
+    (i32.const 5)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.load16_s
+     (i32.const 6)
+    )
+    (i32.const 65534)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.load16_u
+     (i32.const 7)
+    )
+    (i32.const 1)
+   )
+  )
+  (i32.store8
+   (i32.const 8)
+   (i32.const -1)
+  )
+  (i32.store8
+   (i32.const 9)
+   (i32.and
+    (i32.const -2)
+    (i32.const 254)
+   )
+  )
+  (i32.store16
+   (i32.const 10)
+   (i32.const -3)
+  )
+  (i32.store16
+   (i32.const 11)
+   (i32.and
+    (i32.const -4)
+    (i32.const 65534)
+   )
+  )
+  (i64.store8
+   (i32.const 11)
+   (i64.const 1)
+  )
+  (i64.store16
+   (i32.const 11)
+   (i64.const 2)
+  )
+  (i64.store32
+   (i32.const 11)
+   (i64.const 3)
+  )
+  (i32.store8
+   (i32.const 7)
+   (i32.const 255)
+  )
+  (i32.store8
+   (i32.const 8)
+   (i32.const 255)
+  )
+  (i32.store8
+   (i32.const 9)
+   (i32.const 0)
+  )
+  (i32.store16
+   (i32.const 10)
+   (i32.const 65535)
+  )
+  (i32.store16
+   (i32.const 11)
+   (i32.const 0)
+  )
+  (i32.store16
+   (i32.const 13)
+   (i32.const 65535)
+  )
+  (i32.store
+   (i32.const 14)
+   (i32.const 65536)
+  )
+  (i64.store8
+   (i32.const 8)
+   (i64.const 255)
+  )
+  (i64.store8
+   (i32.const 9)
+   (i64.const 0)
+  )
+  (i64.store16
+   (i32.const 10)
+   (i64.const 65535)
+  )
+  (i64.store16
+   (i32.const 11)
+   (i64.const 0)
+  )
+  (i64.store32
+   (i32.const 12)
+   (i64.const 4294967295)
+  )
+  (i64.store32
+   (i32.const 13)
+   (i64.const 0)
+  )
+  (i64.store
+   (i32.const 14)
+   (i64.const 4294967296)
+  )
+ )
+ (func $and-neg1
+  (drop
+   (i32.const 100)
+  )
+  (drop
+   (i32.and
+    (i32.const 100)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $and-pos1
+  (drop
+   (i32.eqz
+    (i32.const 1000)
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.const 1000)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.const 100)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.lt_u
+    (i32.const 2000)
+    (i32.const 3000)
+   )
+  )
+ )
+ (func $canonicalize (param $x i32) (param $y i32) (param $fx f64) (param $fy f64)
+  (drop
+   (i32.and
+    (unreachable)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.const 1)
+    (unreachable)
+   )
+  )
+  (drop
+   (i32.div_s
+    (unreachable)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.div_s
+    (i32.const 1)
+    (unreachable)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.const 1)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (i32.const 3)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (i32.const 4)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.and
+    (local.tee $x
+     (i32.const -4)
+    )
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.and
+    (block $block (result i32)
+     (i32.const -5)
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.and
+    (block $block3 (result i32)
+     (i32.const -6)
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.and
+    (block $block4 (result i32)
+     (i32.const 5)
+    )
+    (loop $loop-in (result i32)
+     (i32.const 6)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (block $block6 (result i32)
+     (i32.const 8)
+    )
+    (loop $loop-in5 (result i32)
+     (i32.const 7)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (block $block8 (result i32)
+     (i32.const 10)
+    )
+    (loop $loop-in7 (result i32)
+     (call $and-pos1)
+     (i32.const 9)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (block $block10 (result i32)
+     (call $and-pos1)
+     (i32.const 12)
+    )
+    (loop $loop-in9 (result i32)
+     (i32.const 11)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (loop $loop-in11 (result i32)
+     (call $and-pos1)
+     (i32.const 13)
+    )
+    (block $block12 (result i32)
+     (call $and-pos1)
+     (i32.const 14)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (block $block13 (result i32)
+     (call $and-pos1)
+     (i32.const 14)
+    )
+    (loop $loop-in14 (result i32)
+     (call $and-pos1)
+     (i32.const 13)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (block $block15 (result i32)
+     (i32.const 15)
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.and
+    (block $block16 (result i32)
+     (i32.const 15)
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.gt_u
+     (i32.const 16)
+     (i32.const 17)
+    )
+    (i32.gt_u
+     (i32.const 18)
+     (i32.const 19)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (i32.gt_u
+     (i32.const 20)
+     (i32.const 21)
+    )
+    (i32.gt_u
+     (i32.const 22)
+     (i32.const 23)
+    )
+   )
+  )
+  (drop
+   (i32.lt_s
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (i32.const -1)
+   )
+  )
+  (drop
+   (f64.ne
+    (local.get $fx)
+    (f64.const -1)
+   )
+  )
+  (drop
+   (f64.gt
+    (local.get $fx)
+    (f64.const -2)
+   )
+  )
+  (drop
+   (f64.le
+    (local.get $fx)
+    (f64.const inf)
+   )
+  )
+  (drop
+   (f64.ge
+    (local.get $fx)
+    (f64.const nan:0x8000000000000)
+   )
+  )
+  (drop
+   (f64.ge
+    (f64.const 1)
+    (f64.const 2)
+   )
+  )
+  (drop
+   (i32.add
+    (i32.ctz
+     (local.get $x)
+    )
+    (i32.ctz
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.add
+    (i32.ctz
+     (local.get $y)
+    )
+    (i32.ctz
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (i32.add
+    (i32.ctz
+     (local.get $x)
+    )
+    (i32.eqz
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.add
+    (i32.ctz
+     (local.get $y)
+    )
+    (i32.eqz
+     (local.get $x)
+    )
+   )
+  )
+ )
+ (func $ne0 (result i32)
+  (if
+   (call $ne0)
+   (nop)
+  )
+  (if
+   (call $ne0)
+   (nop)
+  )
+  (if
+   (i32.or
+    (call $ne0)
+    (call $ne0)
+   )
+   (nop)
+  )
+  (if
+   (i32.and
+    (i32.ne
+     (call $ne0)
+     (i32.const 0)
+    )
+    (i32.ne
+     (call $ne0)
+     (i32.const 0)
+    )
+   )
+   (nop)
+  )
+  (i32.const 1)
+ )
+ (func $recurse-bool
+  (if
+   (if (result i32)
+    (i32.const 1)
+    (call $ne0)
+    (call $ne1)
+   )
+   (nop)
+  )
+  (if
+   (block $block (result i32)
+    (nop)
+    (call $ne0)
+   )
+   (nop)
+  )
+ )
+ (func $ne1 (result i32)
+  (unreachable)
+ )
+ (func $load-off-2 (param $0 i32) (result i32)
+  (i32.store
+   (i32.const 6)
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const 6)
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.add
+    (local.get $0)
+    (i32.const 5)
+   )
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.add
+    (local.get $0)
+    (i32.const 7)
+   )
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.sub
+    (local.get $0)
+    (i32.const 11)
+   )
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.sub
+    (local.get $0)
+    (i32.const 13)
+   )
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const 4)
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.const -2)
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const 25)
+   (local.get $0)
+  )
+  (i32.store offset=2
+   (i32.const -25)
+   (local.get $0)
+  )
+  (drop
+   (i32.load
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.load offset=2
+    (i32.add
+     (local.get $0)
+     (i32.const 6)
+    )
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 10)
+   )
+  )
+  (i32.load offset=2
+   (i32.add
+    (local.get $0)
+    (i32.const 10)
+   )
+  )
+ )
+ (func $sign-ext (param $0 i32) (param $1 i32)
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $0)
+     (i32.const 255)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $0)
+     (i32.const 65535)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $0)
+     (i32.const 134217727)
+    )
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.and
+     (local.get $0)
+     (i32.const 255)
+    )
+    (i32.const 100)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $0)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $0)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.and
+     (local.get $0)
+     (i32.const 255)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 255)
+    )
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.and
+     (local.get $0)
+     (i32.const 65535)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 65535)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.shr_s
+     (i32.shl
+      (local.get $0)
+      (i32.const 24)
+     )
+     (i32.const 23)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.shr_u
+     (i32.shl
+      (local.get $0)
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+   )
+  )
+  (drop
+   (i32.lt_s
+    (i32.shr_s
+     (i32.shl
+      (local.get $0)
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.shr_s
+     (i32.shl
+      (unreachable)
+      (i32.const 16)
+     )
+     (i32.const 16)
+    )
+    (i32.const 111)
+    (i32.const 222)
+   )
+  )
+ )
+ (func $sign-ext-input (param $0 i32) (param $1 i32)
+  (drop
+   (i32.const 100)
+  )
+  (drop
+   (i32.const 127)
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.const 128)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (unreachable)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.const 1)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.const 127)
+    (i32.const 128)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.and
+      (i32.const 128)
+      (i32.const 129)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.xor
+    (i32.const 127)
+    (i32.const 126)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.xor
+      (i32.const 127)
+      (i32.const 128)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.or
+    (i32.const 127)
+    (i32.const 126)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.or
+      (i32.const 127)
+      (i32.const 128)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.const 32)
+     (i32.const 26)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shl
+    (i32.const 32)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.const 32)
+     (i32.const 27)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.shr_u
+      (i32.const 256)
+      (i32.const 1)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.const 256)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.const 128)
+    (i32.const 3)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.shr_u
+      (i32.const 256)
+      (i32.const 1)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.const 256)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.const 128)
+    (i32.const 3)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.const -1)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.and
+     (i32.const -1)
+     (i32.const 2147483647)
+    )
+    (i32.const 31)
+   )
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (f32.le
+    (f32.const -1)
+    (f32.const -1)
+   )
+  )
+  (drop
+   (i32.clz
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.clz
+      (i32.const 0)
+     )
+     (i32.const 26)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.clz
+      (i32.const 0)
+     )
+     (i32.const 27)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.wrap_i64
+    (i64.clz
+     (i64.const 0)
+    )
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.wrap_i64
+      (i64.clz
+       (i64.const 0)
+      )
+     )
+     (i32.const 25)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.wrap_i64
+      (i64.clz
+       (i64.const 0)
+      )
+     )
+     (i32.const 26)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.const -1)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.shr_u
+      (i32.wrap_i64
+       (i64.const -1)
+      )
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.wrap_i64
+     (i64.const -1)
+    )
+    (i32.const 25)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.shr_u
+      (i32.wrap_i64
+       (i64.extend_i32_s
+        (i32.const -1)
+       )
+      )
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.wrap_i64
+     (i64.extend_i32_s
+      (i32.const -1)
+     )
+    )
+    (i32.const 25)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.xor
+      (local.get $0)
+      (i32.le_u
+       (local.get $0)
+       (i32.const 2)
+      )
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func $linear-sums (param $0 i32) (param $1 i32)
+  (drop
+   (i32.add
+    (i32.shl
+     (local.get $0)
+     (i32.const 4)
+    )
+    (local.get $1)
+   )
+  )
+  (drop
+   (i32.add
+    (i32.add
+     (local.get $1)
+     (i32.shl
+      (local.get $0)
+      (i32.const 3)
+     )
+    )
+    (i32.const 12)
+   )
+  )
+  (drop
+   (i32.const 4)
+  )
+  (drop
+   (i32.const 18)
+  )
+  (drop
+   (i32.const 6)
+  )
+  (drop
+   (i32.const -4)
+  )
+  (drop
+   (i32.const 2)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 26)
+  )
+  (drop
+   (i32.const -20)
+  )
+  (drop
+   (i32.const 22)
+  )
+  (drop
+   (i32.add
+    (i32.shl
+     (i32.const 1)
+     (local.get $0)
+    )
+    (i32.const 14)
+   )
+  )
+  (drop
+   (i32.sub
+    (i32.shl
+     (local.get $1)
+     (i32.const 3)
+    )
+    (i32.const 66)
+   )
+  )
+  (drop
+   (i32.const 44)
+  )
+  (drop
+   (i32.add
+    (i32.mul
+     (local.get $0)
+     (i32.const 10)
+    )
+    (i32.const 14)
+   )
+  )
+  (drop
+   (i32.add
+    (i32.shl
+     (local.get $0)
+     (i32.const 1)
+    )
+    (i32.const 34)
+   )
+  )
+  (drop
+   (local.get $0)
+  )
+ )
+ (func $almost-sign-ext (param $0 i32)
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.const 100)
+     (i32.const 25)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shl
+    (i32.const 50)
+    (i32.const 1)
+   )
+  )
+ )
+ (func $squaring (param $0 i32) (param $1 i32)
+  (drop
+   (i32.and
+    (local.get $0)
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $0)
+    (i32.const 11)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $0)
+    (i32.const 8)
+   )
+  )
+  (drop
+   (i32.or
+    (local.get $0)
+    (i32.const 203)
+   )
+  )
+  (drop
+   (i32.shl
+    (local.get $0)
+    (i32.const 19)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (local.get $0)
+    (i32.const 19)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (local.get $0)
+    (i32.const 19)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.shr_s
+     (local.get $0)
+     (i32.const 11)
+    )
+    (i32.const 8)
+   )
+  )
+ )
+ (func $sign-ext-ne (param $0 i32) (param $1 i32)
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $0)
+    )
+    (i32.const 1)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $0)
+    )
+    (i32.const 1)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $0)
+    )
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.ne
+    (i32.and
+     (local.get $0)
+     (i32.const 255)
+    )
+    (i32.const 111)
+   )
+  )
+  (drop
+   (i32.ne
+    (i32.and
+     (local.get $0)
+     (i32.const 255)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 255)
+    )
+   )
+  )
+ )
+ (func $sign-ext-eqz (param $0 i32) (param $1 i32)
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $0)
+     (i32.const 255)
+    )
+   )
+  )
+ )
+ (func $sign-ext-boolean (param $0 i32) (param $1 i32)
+  (drop
+   (if (result i32)
+    (i32.and
+     (local.get $0)
+     (i32.const 255)
+    )
+    (i32.const 100)
+    (i32.const 200)
+   )
+  )
+ )
+ (func $add-sub-zero (param $0 i32) (param $1 i64)
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $0)
+  )
+  (drop
+   (local.get $1)
+  )
+  (drop
+   (local.get $1)
+  )
+ )
+ (func $store-signext (param $0 i32)
+  (i32.store8
+   (i32.const 8)
+   (local.get $0)
+  )
+  (i32.store8
+   (i32.const 8)
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 25)
+    )
+    (i32.const 25)
+   )
+  )
+  (i32.store8
+   (i32.const 8)
+   (local.get $0)
+  )
+  (i32.store16
+   (i32.const 8)
+   (local.get $0)
+  )
+  (i32.store16
+   (i32.const 8)
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 17)
+    )
+    (i32.const 17)
+   )
+  )
+  (i32.store16
+   (i32.const 8)
+   (local.get $0)
+  )
+  (i32.store
+   (i32.const 8)
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 16)
+    )
+    (i32.const 16)
+   )
+  )
+  (i32.store
+   (i32.const 8)
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 8)
+    )
+    (i32.const 8)
+   )
+  )
+ )
+ (func $sign-ext-tee (param $0 i32) (param $1 i32)
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.tee $0
+      (i32.const 128)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (local.tee $0
+    (i32.const 127)
+   )
+  )
+ )
+ (func $sign-ext-load (param $0 i32) (param $1 i32)
+  (drop
+   (i32.load8_s
+    (i32.const 256)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.shr_u
+      (i32.load8_s
+       (i32.const 256)
+      )
+      (i32.const 1)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.load8_u
+     (i32.const 256)
+    )
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load16_s
+    (i32.const 256)
+   )
+  )
+  (drop
+   (local.tee $1
+    (i32.load8_s
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.tee $1
+      (i32.load8_u
+       (i32.const 1)
+      )
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.and
+    (local.tee $1
+     (i32.load8_s
+      (i32.const 1)
+     )
+    )
+    (i32.const 255)
+   )
+  )
+  (drop
+   (local.tee $1
+    (i32.load8_u
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $mask-bits (param $0 i32) (param $1 i32)
+  (drop
+   (local.tee $0
+    (i32.const 127)
+   )
+  )
+  (drop
+   (local.tee $0
+    (i32.const 128)
+   )
+  )
+  (drop
+   (i32.and
+    (local.tee $0
+     (i32.const 128)
+    )
+    (i32.const 254)
+   )
+  )
+  (drop
+   (i32.and
+    (local.tee $0
+     (i32.const 128)
+    )
+    (i32.const 1279)
+   )
+  )
+  (drop
+   (i32.and
+    (local.tee $0
+     (i32.const 128)
+    )
+    (i32.const 1290)
+   )
+  )
+  (drop
+   (local.tee $0
+    (i32.const 128)
+   )
+  )
+  (drop
+   (local.tee $0
+    (i32.const 128)
+   )
+  )
+  (drop
+   (i32.and
+    (local.tee $0
+     (i32.const 128)
+    )
+    (i32.const 127)
+   )
+  )
+ )
+ (func $local-info-zero-ext (param $0 i32) (param $1 i32)
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $w i32)
+  (local.set $x
+   (i32.const 212)
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $y
+   (i32.const 500)
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.const 255)
+   )
+  )
+  (local.set $0
+   (i32.const 212)
+  )
+  (drop
+   (i32.and
+    (local.get $0)
+    (i32.const 255)
+   )
+  )
+  (local.set $z
+   (i32.const 212)
+  )
+  (local.set $z
+   (i32.const 220)
+  )
+  (drop
+   (local.get $z)
+  )
+  (local.set $w
+   (i32.const 212)
+  )
+  (local.set $w
+   (i32.const 1000)
+  )
+  (drop
+   (i32.and
+    (local.get $w)
+    (i32.const 255)
+   )
+  )
+ )
+ (func $local-info-sign-ext-bitsize (param $0 i32) (param $1 i32)
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $w i32)
+  (local.set $x
+   (i32.const 127)
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $y
+   (i32.const 128)
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $y)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (local.set $0
+   (i32.const 127)
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (local.set $z
+   (i32.const 127)
+  )
+  (local.set $z
+   (i32.const 100)
+  )
+  (drop
+   (local.get $z)
+  )
+  (local.set $w
+   (i32.const 127)
+  )
+  (local.set $w
+   (i32.const 150)
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $w)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func $local-info-sign-ext-already-exted (param $0 i32) (param $1 i32)
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $w i32)
+  (local.set $x
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $y
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 16)
+    )
+    (i32.const 16)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $y)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (local.set $0
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (local.set $z
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (local.set $z
+   (i32.shr_s
+    (i32.shl
+     (local.get $1)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (local.get $z)
+  )
+  (local.set $w
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (local.set $w
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 23)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $w)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 23)
+   )
+  )
+ )
+ (func $signed-loads-fill-the-bits (param $$e i32) (result i32)
+  (local $$0 i32)
+  (local $$conv i32)
+  (local.set $$0
+   (i32.load8_s
+    (i32.const 1024)
+   )
+  )
+  (local.set $$conv
+   (i32.and
+    (local.get $$0)
+    (i32.const 255)
+   )
+  )
+  (return
+   (i32.eq
+    (local.get $$e)
+    (local.get $$conv)
+   )
+  )
+ )
+ (func $local-info-sign-ext-already-exted-by-load (param $0 i32) (param $1 i32)
+  (local $x i32)
+  (local $y i32)
+  (local $z i32)
+  (local $w i32)
+  (local.set $x
+   (i32.load8_s
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (local.set $y
+   (i32.load8_u
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $y)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+  (local.set $z
+   (i32.load16_s
+    (i32.const 1024)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (local.get $z)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func $compare-load-s-sign-extend (param $0 i32) (param $1 i32)
+  (drop
+   (i32.eq
+    (i32.load8_u
+     (local.get $0)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 255)
+    )
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.load8_u
+     (local.get $0)
+    )
+    (i32.and
+     (local.get $1)
+     (i32.const 255)
+    )
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.load8_u
+     (local.get $0)
+    )
+    (i32.shr_s
+     (i32.shl
+      (local.get $1)
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.load8_s
+     (local.get $0)
+    )
+    (i32.shr_s
+     (i32.shl
+      (local.get $1)
+      (i32.const 16)
+     )
+     (i32.const 16)
+    )
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.load8_u
+     (local.get $0)
+    )
+    (i32.shr_s
+     (i32.shl
+      (local.get $1)
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.load8_s
+     (local.get $0)
+    )
+    (i32.shr_s
+     (i32.shl
+      (local.get $1)
+      (i32.const 16)
+     )
+     (i32.const 16)
+    )
+   )
+  )
+ )
+ (func $unsign-diff-sizes (param $x i32) (param $y i32) (result i32)
+  (i32.ne
+   (i32.shr_s
+    (i32.shl
+     (call $unsign-diff-sizes
+      (i32.const -1)
+      (i32.const 5)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+   (i32.shr_s
+    (i32.shl
+     (call $unsign-diff-sizes
+      (i32.const 1)
+      (i32.const 2006)
+     )
+     (i32.const 16)
+    )
+    (i32.const 16)
+   )
+  )
+ )
+ (func $unsign-same-sizes (param $x i32) (param $y i32) (result i32)
+  (i32.ne
+   (i32.and
+    (call $unsign-same-sizes
+     (i32.const -1)
+     (i32.const 5)
+    )
+    (i32.const 255)
+   )
+   (i32.and
+    (call $unsign-same-sizes
+     (i32.const 1)
+     (i32.const 2006)
+    )
+    (i32.const 255)
+   )
+  )
+ )
+ (func $fuzz-almost-sign-ext
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.load16_u
+      (i32.const 2278)
+     )
+     (i32.const 17)
+    )
+    (i32.const 16)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.load16_u
+      (i32.const 2278)
+     )
+     (i32.const 17)
+    )
+    (i32.const 16)
+   )
+  )
+ )
+ (func $fuzz-comp-impossible (param $x i32)
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $x)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $x)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.and
+     (local.get $x)
+     (i32.const 255)
+    )
+    (i32.const 127)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $x)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $x)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.get $x)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.and
+     (local.get $x)
+     (i32.const 255)
+    )
+    (i32.const 252)
+   )
+  )
+ )
+ (func $if-parallel (param $0 i32) (param $1 i32)
+  (drop
+   (i32.add
+    (local.get $1)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.tee $0
+      (local.get $1)
+     )
+    )
+    (i32.add
+     (local.get $1)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (i32.add
+     (local.get $1)
+     (unreachable)
+    )
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.tee $0
+      (local.get $1)
+     )
+    )
+    (i32.add
+     (local.get $1)
+     (unreachable)
+    )
+   )
+  )
+  (drop
+   (if (result i32)
+    (unreachable)
+    (i32.add
+     (local.get $1)
+     (unreachable)
+    )
+    (i32.add
+     (local.get $1)
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $select-parallel (param $0 i32) (param $1 i32)
+  (drop
+   (i32.add
+    (local.get $1)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (select
+    (local.tee $0
+     (local.get $1)
+    )
+    (local.tee $0
+     (local.get $1)
+    )
+    (local.get $0)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.tee $0
+      (local.get $1)
+     )
+    )
+    (i32.add
+     (local.get $1)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (select
+    (local.tee $0
+     (local.get $1)
+    )
+    (local.tee $0
+     (local.get $1)
+    )
+    (local.tee $0
+     (local.get $1)
+    )
+   )
+  )
+  (drop
+   (select
+    (local.tee $0
+     (local.get $1)
+    )
+    (local.tee $0
+     (local.get $1)
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $zero-shifts-is-not-sign-ext
+  (drop
+   (i32.eq
+    (i32.load16_s align=1
+     (i32.const 790656516)
+    )
+    (i32.const -5431187)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.shl
+     (i32.load16_s align=1
+      (i32.const 790656516)
+     )
+     (i32.const 1)
+    )
+    (i32.const -5431187)
+   )
+  )
+ )
+ (func $zero-ops (result i32)
+  (return
+   (i32.eq
+    (i32.load16_s align=1
+     (i32.const 790656516)
+    )
+    (i32.const -1337)
+   )
+  )
+ )
+ (func $zero-ops-64 (result i32)
+  (return
+   (i64.eq
+    (i64.load16_s align=1
+     (i32.const 790656516)
+    )
+    (i64.const -1337)
+   )
+  )
+ )
+ (func $zero-ops-64-special (result i32)
+  (return
+   (i32.wrap_i64
+    (i64.popcnt
+     (i64.const 7377)
+    )
+   )
+  )
+ )
+ (func $sign-ext-1-and-ne (result i32)
+  (drop
+   (call $sign-ext-1-and-ne)
+  )
+  (i32.const 1)
+ )
+ (func $neg-shifts-and-255 (result i32)
+  (i32.and
+   (i32.const -99)
+   (i32.const 255)
+  )
+ )
+ (func $neg-shifts-and-255-b (result i32)
+  (i32.and
+   (i32.const -2349025)
+   (i32.const 255)
+  )
+ )
+ (func $shifts-square-overflow (param $x i32) (result i32)
+  (i32.shr_u
+   (i32.shr_u
+    (local.get $x)
+    (i32.const 31)
+   )
+   (i32.const 31)
+  )
+ )
+ (func $shifts-square-no-overflow-small (param $x i32) (result i32)
+  (i32.shr_u
+   (local.get $x)
+   (i32.const 9)
+  )
+ )
+ (func $shifts-square-overflow-64 (param $x i64) (result i64)
+  (i64.shr_u
+   (i64.shr_u
+    (local.get $x)
+    (i64.const 63)
+   )
+   (i64.const 63)
+  )
+ )
+ (func $shifts-square-no-overflow-small-64 (param $x i64) (result i64)
+  (i64.shr_u
+   (local.get $x)
+   (i64.const 9)
+  )
+ )
+ (func $shifts-square-unreachable (param $x i32) (result i32)
+  (i32.shr_u
+   (i32.shr_u
+    (unreachable)
+    (i32.const 1031)
+   )
+   (i32.const 4098)
+  )
+ )
+ (func $mix-shifts (result i32)
+  (i32.shr_u
+   (i32.shl
+    (i32.const 23)
+    (i32.const 3)
+   )
+   (i32.const 8)
+  )
+ )
+ (func $actually-no-shifts (result i32)
+  (i32.const 33)
+ )
+ (func $less-shifts-than-it-seems (param $x i32) (result i32)
+  (i32.const 4800)
+ )
+ (func $and-popcount32 (result i32)
+  (i32.and
+   (i32.popcnt
+    (i32.const -1)
+   )
+   (i32.const 31)
+  )
+ )
+ (func $and-popcount32-big (result i32)
+  (i32.popcnt
+   (i32.const -1)
+  )
+ )
+ (func $and-popcount64 (result i64)
+  (i64.and
+   (i64.popcnt
+    (i64.const -1)
+   )
+   (i64.const 63)
+  )
+ )
+ (func $and-popcount64-big (result i64)
+  (i64.and
+   (i64.popcnt
+    (i64.const -1)
+   )
+   (i64.const 127)
+  )
+ )
+ (func $and-popcount64-bigger (result i64)
+  (i64.and
+   (i64.popcnt
+    (i64.const -1)
+   )
+   (i64.const 255)
+  )
+ )
+ (func $optimizeAddedConstants-filters-through-nonzero (result i32)
+  (i32.sub
+   (i32.shl
+    (i32.const -536870912)
+    (i32.wrap_i64
+     (i64.const 0)
+    )
+   )
+   (i32.const 31744)
+  )
+ )
+ (func $optimizeAddedConstants-filters-through-nonzero-b (result i32)
+  (i32.sub
+   (i32.shl
+    (i32.const -536870912)
+    (i32.wrap_i64
+     (i64.const -1)
+    )
+   )
+   (i32.const 31744)
+  )
+ )
+ (func $return-proper-value-from-shift-left-by-zero (result i32)
+  (if (result i32)
+   (i32.add
+    (loop $label$0 (result i32)
+     (block $label$1
+      (br_if $label$1
+       (i32.load
+        (i32.const 0)
+       )
+      )
+     )
+     (i32.const -62)
+    )
+    (i32.const 40)
+   )
+   (i32.const 1)
+   (i32.const 0)
+  )
+ )
+ (func $de-morgan-2 (param $x i32) (param $y i32)
+  (drop
+   (i32.eqz
+    (i32.or
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.or
+    (i32.eqz
+     (local.get $x)
+    )
+    (i32.eqz
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.xor
+    (i32.eqz
+     (local.get $x)
+    )
+    (i32.eqz
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $y)
+    (i32.eqz
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (i32.eqz
+     (local.get $y)
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.and
+    (i32.eqz
+     (local.get $x)
+    )
+    (i32.wrap_i64
+     (i64.const 2)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (i32.eqz
+     (local.get $y)
+    )
+    (i32.wrap_i64
+     (i64.const 1)
+    )
+   )
+  )
+ )
+ (func $subzero1 (param $0 i32) (result i32)
+  (i32.sub
+   (i32.const 32)
+   (i32.clz
+    (local.get $0)
+   )
+  )
+ )
+ (func $subzero2 (param $0 i32) (result i32)
+  (i32.sub
+   (i32.const 32)
+   (i32.clz
+    (local.get $0)
+   )
+  )
+ )
+ (func $subzero3 (param $0 i32) (param $1 i32) (result i32)
+  (i32.sub
+   (local.get $1)
+   (i32.clz
+    (local.get $0)
+   )
+  )
+ )
+ (func $subzero4 (param $0 i32) (param $1 i32) (result i32)
+  (i32.sub
+   (local.get $0)
+   (i32.clz
+    (local.get $1)
+   )
+  )
+ )
+ (func $mul-32-power-2 (param $x i32) (result i32)
+  (drop
+   (call $mul-32-power-2
+    (i32.shl
+     (local.get $x)
+     (i32.const 2)
+    )
+   )
+  )
+  (drop
+   (call $mul-32-power-2
+    (i32.mul
+     (local.get $x)
+     (i32.const 5)
+    )
+   )
+  )
+  (drop
+   (call $mul-32-power-2
+    (local.get $x)
+   )
+  )
+  (drop
+   (call $mul-32-power-2
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $mul-32-power-2
+    (i32.mul
+     (call $mul-32-power-2
+      (i32.const 123)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+  (drop
+   (call $mul-32-power-2
+    (i32.sub
+     (i32.const 0)
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (call $mul-32-power-2
+    (i32.shl
+     (local.get $x)
+     (i32.const 31)
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $mul-64-power-2 (param $x i64) (result i64)
+  (drop
+   (call $mul-64-power-2
+    (i64.shl
+     (local.get $x)
+     (i64.const 2)
+    )
+   )
+  )
+  (drop
+   (call $mul-64-power-2
+    (i64.mul
+     (local.get $x)
+     (i64.const 5)
+    )
+   )
+  )
+  (drop
+   (call $mul-64-power-2
+    (local.get $x)
+   )
+  )
+  (drop
+   (call $mul-64-power-2
+    (i64.const 0)
+   )
+  )
+  (drop
+   (call $mul-64-power-2
+    (i64.mul
+     (call $mul-64-power-2
+      (i64.const 123)
+     )
+     (i64.const 0)
+    )
+   )
+  )
+  (drop
+   (call $mul-64-power-2
+    (i64.sub
+     (i64.const 0)
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (call $mul-64-power-2
+    (i64.shl
+     (local.get $x)
+     (i64.const 63)
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $div-32-power-2 (param $x i32) (result i32)
+  (drop
+   (call $div-32-power-2
+    (i32.shr_u
+     (local.get $x)
+     (i32.const 2)
+    )
+   )
+  )
+  (drop
+   (call $div-32-power-2
+    (i32.div_u
+     (local.get $x)
+     (i32.const 5)
+    )
+   )
+  )
+  (drop
+   (call $div-32-power-2
+    (local.get $x)
+   )
+  )
+  (drop
+   (call $div-32-power-2
+    (i32.div_u
+     (local.get $x)
+     (i32.const 0)
+    )
+   )
+  )
+  (drop
+   (call $div-32-power-2
+    (i32.div_u
+     (call $div-32-power-2
+      (i32.const 123)
+     )
+     (i32.const 0)
+    )
+   )
+  )
+  (drop
+   (call $div-32-power-2
+    (i32.eq
+     (local.get $x)
+     (i32.const -1)
+    )
+   )
+  )
+  (drop
+   (call $div-32-power-2
+    (i32.shr_u
+     (local.get $x)
+     (i32.const 31)
+    )
+   )
+  )
+  (unreachable)
+ )
+ (func $urem-32-power-2 (param $x i32) (result i32)
+  (drop
+   (call $urem-32-power-2
+    (i32.and
+     (local.get $x)
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (call $urem-32-power-2
+    (i32.rem_u
+     (local.get $x)
+     (i32.const 5)
+    )
+   )
+  )
+  (drop
+   (call $urem-32-power-2
+    (i32.const 0)
+   )
+  )
+  (drop
+   (call $urem-32-power-2
+    (i32.rem_u
+     (local.get $x)
+     (i32.const 0)
+    )
+   )
+  )
+  (drop
+   (call $urem-32-power-2
+    (i32.rem_u
+     (local.get $x)
+     (i32.const -1)
+    )
+   )
+  )
+  (drop
+   (call $urem-32-power-2
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+   )
+  )
+  (drop
+   (call $urem-32-power-2
+    (i32.const 0)
+   )
+  )
+  (unreachable)
+ )
+ (func $fdiv-32-power-2 (param $x f32)
+  (drop
+   (f32.mul
+    (local.get $x)
+    (f32.const 0.5)
+   )
+  )
+  (drop
+   (f32.mul
+    (local.get $x)
+    (f32.const -0.5)
+   )
+  )
+  (drop
+   (f32.mul
+    (local.get $x)
+    (f32.const 2.3283064365386963e-10)
+   )
+  )
+  (drop
+   (f32.mul
+    (local.get $x)
+    (f32.const 5.421010862427522e-20)
+   )
+  )
+  (drop
+   (f32.mul
+    (local.get $x)
+    (f32.const 8507059173023461586584365e13)
+   )
+  )
+  (drop
+   (f32.mul
+    (local.get $x)
+    (f32.const 1.1754943508222875e-38)
+   )
+  )
+  (drop
+   (f32.mul
+    (local.get $x)
+    (f32.const -8507059173023461586584365e13)
+   )
+  )
+  (drop
+   (f32.mul
+    (local.get $x)
+    (f32.const -1.1754943508222875e-38)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $x)
+    (f32.const 5.877471754111438e-39)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $x)
+    (f32.const 5.877471754111438e-39)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $x)
+    (f32.const 0)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $x)
+    (f32.const nan:0x400000)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $x)
+    (f32.const inf)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $x)
+    (f32.const -inf)
+   )
+  )
+ )
+ (func $fdiv-64-power-2 (param $x f64)
+  (drop
+   (f64.mul
+    (local.get $x)
+    (f64.const 0.5)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $x)
+    (f64.const -0.5)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $x)
+    (f64.const 2.3283064365386963e-10)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $x)
+    (f64.const 5.421010862427522e-20)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $x)
+    (f64.const 4494232837155789769323262e283)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $x)
+    (f64.const 2.2250738585072014e-308)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $x)
+    (f64.const -4494232837155789769323262e283)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $x)
+    (f64.const -2.2250738585072014e-308)
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $x)
+    (f64.const 1.1125369292536007e-308)
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $x)
+    (f64.const 8988465674311579538646525e283)
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $x)
+    (f64.const 0)
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $x)
+    (f64.const nan:0x8000000000000)
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $x)
+    (f64.const inf)
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $x)
+    (f64.const -inf)
+   )
+  )
+ )
+ (func $srem-by-const (param $x i32) (param $y i64)
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i64.const 0)
+  )
+  (drop
+   (i32.rem_s
+    (local.get $x)
+    (i32.const -2147483648)
+   )
+  )
+  (drop
+   (i64.rem_s
+    (local.get $y)
+    (i64.const -9223372036854775808)
+   )
+  )
+ )
+ (func $srem-by-pot-eq-ne-zero (param $x i32) (param $y i64)
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $x)
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.and
+     (local.get $y)
+     (i64.const 3)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $x)
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.and
+     (local.get $y)
+     (i64.const 3)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $x)
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.and
+     (local.get $y)
+     (i64.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $x)
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.and
+     (local.get $y)
+     (i64.const 3)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.wrap_i64
+    (i64.and
+     (local.get $y)
+     (i64.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+   )
+  )
+  (drop
+   (i32.ne
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.and
+     (local.get $y)
+     (i64.const 9223372036854775807)
+    )
+   )
+  )
+  (drop
+   (i64.ne
+    (i64.and
+     (local.get $y)
+     (i64.const 9223372036854775807)
+    )
+    (i64.const 0)
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.rem_s
+     (local.get $x)
+     (i32.const 3)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.rem_s
+     (local.get $y)
+     (i64.const 3)
+    )
+   )
+  )
+ )
+ (func $orZero (param $0 i32) (result i32)
+  (local.get $0)
+ )
+ (func $andZero (param $0 i32) (result i32)
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.and
+    (call $andZero
+     (i32.const 1234)
+    )
+    (i32.const 0)
+   )
+  )
+  (unreachable)
+ )
+ (func $abstract-additions (param $x32 i32) (param $x64 i64) (param $y32 f32) (param $y64 f64)
+  (drop
+   (local.get $x32)
+  )
+  (drop
+   (local.get $x32)
+  )
+  (drop
+   (local.get $x32)
+  )
+  (drop
+   (local.get $x32)
+  )
+  (drop
+   (local.get $x64)
+  )
+  (drop
+   (local.get $x64)
+  )
+  (drop
+   (local.get $x64)
+  )
+  (drop
+   (local.get $x64)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i64.const 0)
+  )
+  (drop
+   (f32.mul
+    (local.get $y32)
+    (f32.const 0)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $y64)
+    (f64.const 0)
+   )
+  )
+  (drop
+   (local.get $x32)
+  )
+  (drop
+   (local.get $x64)
+  )
+  (drop
+   (f32.mul
+    (local.get $y32)
+    (f32.const 1)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $y64)
+    (f64.const 1)
+   )
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i64.const 0)
+  )
+  (drop
+   (i32.and
+    (unreachable)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i64.and
+    (unreachable)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (local.get $x32)
+  )
+  (drop
+   (local.get $x32)
+  )
+  (drop
+   (local.get $x64)
+  )
+  (drop
+   (local.get $x64)
+  )
+  (drop
+   (f32.mul
+    (local.get $y32)
+    (f32.const 1)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $y64)
+    (f64.const 1)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $y32)
+    (f32.const 1.2000000476837158)
+   )
+  )
+  (drop
+   (i32.sub
+    (i32.const 0)
+    (local.get $x32)
+   )
+  )
+  (drop
+   (i64.sub
+    (i64.const 0)
+    (local.get $x64)
+   )
+  )
+  (drop
+   (f32.sub
+    (f32.const -0)
+    (local.get $y32)
+   )
+  )
+  (drop
+   (f64.sub
+    (f64.const -0)
+    (local.get $y64)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x32)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.le_u
+    (i32.add
+     (local.get $x32)
+     (i32.const 10)
+    )
+    (i32.const 20)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x32)
+    (i32.const 30)
+   )
+  )
+  (drop
+   (i64.eq
+    (local.get $x64)
+    (i64.const 10)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x32)
+    (i32.const 10)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.add
+     (local.get $x32)
+     (i32.const 10)
+    )
+    (local.get $x32)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x32)
+    (i32.const 30)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.sub
+     (local.get $x32)
+     (i32.const 30)
+    )
+    (local.get $x32)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.add
+     (local.get $x32)
+     (i32.const 30)
+    )
+    (local.get $x32)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.sub
+     (local.get $x32)
+     (i32.const 10)
+    )
+    (local.get $x32)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+ )
+ (func $negatives-are-sometimes-better (param $x i32) (param $y i64) (param $z f32)
+  (drop
+   (i32.sub
+    (local.get $x)
+    (i32.const -64)
+   )
+  )
+  (drop
+   (i32.add
+    (local.get $x)
+    (i32.const -64)
+   )
+  )
+  (drop
+   (i32.sub
+    (local.get $x)
+    (i32.const -8192)
+   )
+  )
+  (drop
+   (i32.sub
+    (local.get $x)
+    (i32.const -1048576)
+   )
+  )
+  (drop
+   (i32.sub
+    (local.get $x)
+    (i32.const -134217728)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const -64)
+   )
+  )
+  (drop
+   (i64.add
+    (local.get $y)
+    (i64.const -64)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const -8192)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const -1048576)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const -134217728)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const -17179869184)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const -2199023255552)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const -281474976710656)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const -36028797018963968)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const -4611686018427387904)
+   )
+  )
+  (drop
+   (f32.add
+    (local.get $z)
+    (f32.const 64)
+   )
+  )
+ )
+ (func $shift-a-zero (param $x i32) (param $y i64) (param $z f32)
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i64.const 0)
+  )
+  (drop
+   (i32.shl
+    (i32.const 0)
+    (unreachable)
+   )
+  )
+ )
+ (func $identical-siblings (param $x i32) (param $y i64) (param $z f64) (param $xx i32)
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i64.const 0)
+  )
+  (drop
+   (f64.sub
+    (local.get $z)
+    (local.get $z)
+   )
+  )
+  (drop
+   (i32.sub
+    (local.get $x)
+    (local.get $xx)
+   )
+  )
+  (drop
+   (i32.sub
+    (unreachable)
+    (unreachable)
+   )
+  )
+  (drop
+   (i32.add
+    (local.get $x)
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i64.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+ )
+ (func $all_ones (param $x i32) (param $y i64)
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (i32.const -1)
+  )
+  (drop
+   (i32.or
+    (local.tee $x
+     (i32.const 1337)
+    )
+    (i32.const -1)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (i64.const -1)
+  )
+ )
+ (func $xor (param $x i32) (param $y i64)
+  (drop
+   (local.get $x)
+  )
+ )
+ (func $select-on-const (param $x i32) (param $y i64)
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (i32.const 3)
+  )
+  (drop
+   (local.tee $x
+    (i32.const 5)
+   )
+  )
+  (drop
+   (block (result i32)
+    (drop
+     (local.tee $x
+      (i32.const 6)
+     )
+    )
+    (i32.const 7)
+   )
+  )
+  (drop
+   (select
+    (i32.const 4)
+    (local.tee $x
+     (i32.const 5)
+    )
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.tee $x
+    (i32.const 6)
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.eqz
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.ge_s
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.lt_s
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.lt_s
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.gt_s
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.le_s
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.ge_s
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i32.eqz
+     (i32.eqz
+      (local.get $x)
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i32.eqz
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i64.eqz
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i32.eqz
+     (i64.eqz
+      (local.get $y)
+     )
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i64.ge_s
+     (local.get $y)
+     (i64.const 0)
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i64.lt_s
+     (local.get $y)
+     (i64.const 0)
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i64.lt_s
+     (local.get $y)
+     (i64.const 0)
+    )
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i64.ge_s
+     (local.get $y)
+     (i64.const 0)
+    )
+   )
+  )
+  (drop
+   (select
+    (i32.const 0)
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (select
+    (i32.const 2)
+    (local.get $x)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (select
+    (local.get $x)
+    (i32.const 2)
+    (local.get $x)
+   )
+  )
+  (drop
+   (select
+    (local.get $y)
+    (i64.const 0)
+    (i64.eqz
+     (i64.const 0)
+    )
+   )
+  )
+  (drop
+   (select
+    (local.get $y)
+    (i64.const 2)
+    (i64.eqz
+     (i64.const 2)
+    )
+   )
+  )
+ )
+ (func $optimize-boolean (param $x i32) (param $y i64)
+  (drop
+   (select
+    (i32.const 1)
+    (i32.const 2)
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.and
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.wrap_i64
+    (i64.shr_u
+     (local.get $y)
+     (i64.const 63)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.shr_u
+     (local.get $x)
+     (i32.const 31)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.shr_u
+     (local.get $y)
+     (i64.const 63)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.shr_u
+     (local.get $y)
+     (i64.const 63)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.eqz
+    (i32.wrap_i64
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.wrap_i64
+    (i64.and
+     (local.get $y)
+     (i64.const 1)
+    )
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.and
+     (local.get $y)
+     (i64.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i64.and
+    (local.get $y)
+    (i64.const 1)
+   )
+  )
+  (drop
+   (i64.const 1)
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i64.ne
+    (local.get $y)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.and
+     (local.get $x)
+     (i32.const 3)
+    )
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+ )
+ (func $optimize-bitwise-oprations (param $x i32) (param $y i32) (param $z i64) (param $w i64)
+  (drop
+   (i32.rotl
+    (i32.const -2)
+    (local.get $x)
+   )
+  )
+  (drop
+   (i64.rotl
+    (i64.const -2)
+    (local.get $z)
+   )
+  )
+ )
+ (func $getFallthrough
+  (local $x0 i32)
+  (local $x1 i32)
+  (local $x2 i32)
+  (local $x3 i32)
+  (local $x4 i32)
+  (local $x5 i32)
+  (local $x6 i32)
+  (local $x7 i32)
+  (local.set $x0
+   (i32.const 1)
+  )
+  (drop
+   (local.get $x0)
+  )
+  (local.set $x1
+   (local.tee $x2
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $x1)
+  )
+  (local.set $x3
+   (loop $loop-in (result i32)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (local.get $x3)
+  )
+  (local.set $x4
+   (if (result i32)
+    (i32.const 1)
+    (i32.const 2)
+    (i32.const 3)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x4)
+    (i32.const 7)
+   )
+  )
+  (local.set $x5
+   (if (result i32)
+    (i32.const 1)
+    (unreachable)
+    (i32.const 3)
+   )
+  )
+  (drop
+   (local.get $x5)
+  )
+  (local.set $x6
+   (if (result i32)
+    (i32.const 1)
+    (i32.const 3)
+    (unreachable)
+   )
+  )
+  (drop
+   (local.get $x6)
+  )
+  (drop
+   (block $out (result i32)
+    (local.set $x7
+     (br_if $out
+      (i32.const 1)
+      (i32.const 1)
+     )
+    )
+    (drop
+     (local.get $x7)
+    )
+    (unreachable)
+   )
+  )
+ )
+ (func $tee-with-unreachable-value (result f64)
+  (local $var$0 i32)
+  (block $label$1 (result f64)
+   (local.tee $var$0
+    (br_if $label$1
+     (f64.const 1)
+     (unreachable)
+    )
+   )
+  )
+ )
+ (func $add-sub-zero-reorder-1 (param $temp i32) (result i32)
+  (i32.add
+   (i32.add
+    (i32.sub
+     (i32.const 0)
+     (local.get $temp)
+    )
+    (local.tee $temp
+     (i32.const 1)
+    )
+   )
+   (i32.const 2)
+  )
+ )
+ (func $add-sub-zero-reorder-2 (param $temp i32) (result i32)
+  (i32.add
+   (i32.sub
+    (local.tee $temp
+     (i32.const 1)
+    )
+    (local.get $temp)
+   )
+   (i32.const 2)
+  )
+ )
+ (func $const-float-zero (param $fx f32) (param $fy f64)
+  (drop
+   (f32.sub
+    (local.get $fx)
+    (f32.const 0)
+   )
+  )
+  (drop
+   (f64.sub
+    (local.get $fy)
+    (f64.const 0)
+   )
+  )
+  (drop
+   (f32.add
+    (local.get $fx)
+    (f32.const -0)
+   )
+  )
+  (drop
+   (f64.add
+    (local.get $fy)
+    (f64.const -0)
+   )
+  )
+  (drop
+   (f32.add
+    (local.get $fx)
+    (f32.const 0)
+   )
+  )
+  (drop
+   (f64.add
+    (local.get $fy)
+    (f64.const 0)
+   )
+  )
+  (drop
+   (f32.sub
+    (f32.const 0)
+    (local.get $fx)
+   )
+  )
+  (drop
+   (f64.sub
+    (f64.const 0)
+    (local.get $fy)
+   )
+  )
+  (drop
+   (f32.add
+    (local.get $fx)
+    (f32.const 0)
+   )
+  )
+  (drop
+   (f64.add
+    (local.get $fy)
+    (f64.const 0)
+   )
+  )
+  (drop
+   (f32.sub
+    (f32.const -nan:0x34546d)
+    (f32.const 0)
+   )
+  )
+ )
+ (func $rhs-is-neg-one (param $x i32) (param $y i64) (param $fx f32) (param $fy f64)
+  (drop
+   (i32.add
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i64.add
+    (local.get $y)
+    (i64.const 1)
+   )
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.gt_s
+    (local.get $x)
+    (i32.const -1)
+   )
+  )
+  (drop
+   (i64.gt_s
+    (local.get $y)
+    (i64.const -1)
+   )
+  )
+  (drop
+   (i64.extend_i32_s
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.le_s
+    (local.get $x)
+    (i32.const -1)
+   )
+  )
+  (drop
+   (i64.le_s
+    (local.get $y)
+    (i64.const -1)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const -1)
+   )
+  )
+  (drop
+   (i64.eq
+    (local.get $y)
+    (i64.const -1)
+   )
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (i32.const -1)
+   )
+  )
+  (drop
+   (i64.ne
+    (local.get $y)
+    (i64.const -1)
+   )
+  )
+  (drop
+   (i32.sub
+    (i32.const 0)
+    (local.get $x)
+   )
+  )
+  (drop
+   (i64.sub
+    (i64.const 0)
+    (local.get $y)
+   )
+  )
+  (drop
+   (f32.sub
+    (f32.const -0)
+    (local.get $fx)
+   )
+  )
+  (drop
+   (f64.sub
+    (f64.const -0)
+    (local.get $fy)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const -1)
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i64.eq
+     (local.get $y)
+     (i64.const -1)
+    )
+   )
+  )
+ )
+ (func $rhs-is-const (param $x i32) (param $y i64) (param $fx f32) (param $fy f64)
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const -2147483648)
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i64.eq
+     (local.get $y)
+     (i64.const -9223372036854775808)
+    )
+   )
+  )
+  (drop
+   (i64.div_s
+    (local.get $y)
+    (i64.const -2147483648)
+   )
+  )
+  (drop
+   (i32.ge_u
+    (local.get $x)
+    (i32.const -2)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const -1)
+   )
+  )
+  (drop
+   (i32.ge_u
+    (local.get $x)
+    (i32.const -2147483647)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (local.get $x)
+    (i32.const 31)
+   )
+  )
+  (drop
+   (i64.extend_i32_u
+    (i64.eq
+     (local.get $y)
+     (i64.const -1)
+    )
+   )
+  )
+  (drop
+   (i64.shr_u
+    (local.get $y)
+    (i64.const 63)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i64.ne
+    (local.get $y)
+    (i64.const 0)
+   )
+  )
+  (drop
+   (i32.eqz
+    (local.get $x)
+   )
+  )
+  (drop
+   (i64.eqz
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (i32.const 2147483647)
+   )
+  )
+  (drop
+   (i64.ne
+    (local.get $y)
+    (i64.const 9223372036854775807)
+   )
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (i32.const -2147483648)
+   )
+  )
+  (drop
+   (i64.ne
+    (local.get $y)
+    (i64.const -9223372036854775808)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const -2147483648)
+   )
+  )
+  (drop
+   (i64.eq
+    (local.get $y)
+    (i64.const -9223372036854775808)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const 2147483647)
+   )
+  )
+  (drop
+   (i64.eq
+    (local.get $y)
+    (i64.const 9223372036854775807)
+   )
+  )
+  (drop
+   (f32.sub
+    (f32.const -0)
+    (local.get $fx)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $fy)
+    (f64.const 2.1)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $fy)
+    (f64.const -2)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $fx)
+    (f32.const -inf)
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $fy)
+    (f64.const 0)
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $fy)
+    (f64.const -nan:0x8000000000000)
+   )
+  )
+  (drop
+   (f64.div
+    (f64.const -5)
+    (local.get $fy)
+   )
+  )
+ )
+ (func $lhs-is-neg-one (param $x i32) (param $y i64)
+  (drop
+   (i32.const -1)
+  )
+  (drop
+   (i64.const -1)
+  )
+  (drop
+   (i32.const -1)
+  )
+  (drop
+   (i64.const -1)
+  )
+  (drop
+   (i32.const -1)
+  )
+  (drop
+   (i64.const -1)
+  )
+  (drop
+   (i32.shr_s
+    (i32.const -1)
+    (call $ne0)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.const -1)
+    (local.get $x)
+   )
+  )
+ )
+ (func $lhs-is-const (param $x i32) (param $y i64)
+  (drop
+   (i32.sub
+    (i32.const 1)
+    (local.get $x)
+   )
+  )
+  (drop
+   (i64.sub
+    (i64.const 1)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.sub
+    (i32.const -2)
+    (local.get $x)
+   )
+  )
+  (drop
+   (i64.sub
+    (i64.const -2)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.sub
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i64.sub
+    (local.get $y)
+    (i64.const 1)
+   )
+  )
+  (drop
+   (i32.sub
+    (local.get $x)
+    (i32.const -2147483648)
+   )
+  )
+ )
+ (func $pre-combine-or (param $x i32) (param $y i32)
+  (drop
+   (i32.ge_s
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.ge_s
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.or
+    (i32.eq
+     (local.get $x)
+     (i32.const 1)
+    )
+    (i32.gt_s
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.or
+    (i32.eq
+     (local.get $x)
+     (local.get $y)
+    )
+    (i32.gt_s
+     (local.get $x)
+     (i32.const 1)
+    )
+   )
+  )
+  (drop
+   (i32.or
+    (i32.gt_s
+     (call $ne0)
+     (local.get $y)
+    )
+    (i32.eq
+     (call $ne0)
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.or
+    (i32.lt_s
+     (call $ne0)
+     (local.get $y)
+    )
+    (i32.eq
+     (call $ne0)
+     (local.get $y)
+    )
+   )
+  )
+ )
+ (func $combine-or (param $x i32) (param $y i32)
+  (drop
+   (i32.ge_s
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+ )
+ (func $select-into-arms (param $x i32) (param $y i32)
+  (if
+   (select
+    (local.get $x)
+    (local.get $y)
+    (local.get $y)
+   )
+   (unreachable)
+  )
+ )
+ (func $optimize-boolean-context (param $x i32) (param $y i32)
+  (if
+   (local.get $x)
+   (unreachable)
+  )
+  (drop
+   (select
+    (local.get $x)
+    (local.get $y)
+    (local.get $x)
+   )
+  )
+ )
+ (func $optimize-relationals (param $x i32) (param $y i32) (param $X i64) (param $Y i64)
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const -2147483647)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const -2147483648)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const 2147483647)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i64.eq
+    (local.get $X)
+    (local.get $Y)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i64.eq
+    (local.get $X)
+    (local.get $Y)
+   )
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i64.ne
+    (local.get $X)
+    (local.get $Y)
+   )
+  )
+  (drop
+   (i32.gt_s
+    (i32.sub
+     (local.get $x)
+     (local.get $y)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.ge_s
+    (i32.sub
+     (local.get $x)
+     (local.get $y)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.const 1)
+  )
+  (drop
+   (i32.lt_s
+    (i32.sub
+     (local.get $x)
+     (local.get $y)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.le_s
+    (i32.sub
+     (local.get $x)
+     (local.get $y)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.const 0)
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.eq
+    (local.get $x)
+    (i32.const -2147483648)
+   )
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (i32.const -2147483648)
+   )
+  )
+  (drop
+   (i32.lt_s
+    (i32.sub
+     (local.get $x)
+     (i32.const -2147483648)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.ge_s
+    (i32.sub
+     (local.get $x)
+     (i32.const -2147483648)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.gt_s
+    (i32.sub
+     (local.get $x)
+     (block $block (result i32)
+      (i32.const -2147483648)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (i32.gt_s
+    (i32.sub
+     (local.get $x)
+     (block $block29 (result i32)
+      (i32.const -2147483648)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+ )
+ (func $unsigned-context (param $x i32) (param $y i64)
+  (drop
+   (i32.div_u
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+    (i32.const 3)
+   )
+  )
+  (drop
+   (i32.div_s
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+    (i32.const -3)
+   )
+  )
+  (drop
+   (i32.eq
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+    (i32.const -2147483648)
+   )
+  )
+  (drop
+   (i64.shr_u
+    (i64.and
+     (local.get $y)
+     (i64.const 9223372036854775807)
+    )
+    (i64.const 1)
+   )
+  )
+  (drop
+   (i64.div_s
+    (i64.and
+     (local.get $y)
+     (i64.const 9223372036854775807)
+    )
+    (i64.const -1)
+   )
+  )
+  (drop
+   (i32.rem_u
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+    (i32.const 3)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+    (i32.const 7)
+   )
+  )
+  (drop
+   (i32.ge_u
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+    (i32.const 7)
+   )
+  )
+  (drop
+   (i32.ge_s
+    (i32.and
+     (local.get $x)
+     (i32.const 2147483647)
+    )
+    (i32.const -7)
+   )
+  )
+ )
+ (func $optimize-float-mul-by-two (param $0 f64) (param $1 f32)
+  (drop
+   (f64.add
+    (local.get $0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (f32.add
+    (local.get $1)
+    (local.get $1)
+   )
+  )
+  (drop
+   (f64.mul
+    (call $tee-with-unreachable-value)
+    (f64.const 2)
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $0)
+    (f64.const -2)
+   )
+  )
+ )
+ (func $duplicate-elimination (param $x i32) (param $y i32) (param $z i32) (param $w f64)
+  (drop
+   (f64.abs
+    (local.get $w)
+   )
+  )
+  (drop
+   (f64.ceil
+    (local.get $w)
+   )
+  )
+  (drop
+   (f64.floor
+    (local.get $w)
+   )
+  )
+  (drop
+   (f64.trunc
+    (local.get $w)
+   )
+  )
+  (drop
+   (f64.nearest
+    (local.get $w)
+   )
+  )
+  (drop
+   (f64.nearest
+    (f64.trunc
+     (local.get $w)
+    )
+   )
+  )
+  (drop
+   (f64.trunc
+    (f64.nearest
+     (local.get $w)
+    )
+   )
+  )
+  (drop
+   (local.get $w)
+  )
+  (drop
+   (f64.neg
+    (local.get $w)
+   )
+  )
+  (drop
+   (local.get $w)
+  )
+  (drop
+   (i32.eqz
+    (i32.eqz
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (i32.eqz
+    (local.get $x)
+   )
+  )
+  (drop
+   (i64.eqz
+    (i64.const 1)
+   )
+  )
+  (drop
+   (i32.ne
+    (local.get $x)
+    (i32.const 2)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.rem_s
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.rem_u
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (i32.sub
+    (local.get $y)
+    (i32.sub
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (local.get $y)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.and
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.or
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.or
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.or
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.or
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.or
+    (local.get $z)
+    (i32.or
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.or
+    (local.get $y)
+    (i32.or
+     (local.get $x)
+     (local.get $z)
+    )
+   )
+  )
+  (drop
+   (i32.or
+    (call $ne0)
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.or
+    (i32.or
+     (call $ne0)
+     (local.get $x)
+    )
+    (call $ne0)
+   )
+  )
+  (drop
+   (i32.or
+    (call $ne0)
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.or
+    (call $ne0)
+    (i32.or
+     (call $ne0)
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (i32.rem_s
+    (i32.rem_s
+     (local.get $y)
+     (local.get $x)
+    )
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.rem_u
+    (local.get $y)
+    (i32.rem_u
+     (local.get $x)
+     (local.get $y)
+    )
+   )
+  )
+  (drop
+   (i32.or
+    (local.get $x)
+    (i32.or
+     (local.tee $x
+      (i32.const 1)
+     )
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (i32.or
+    (i32.or
+     (local.get $x)
+     (local.tee $x
+      (i32.const 1)
+     )
+    )
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.xor
+    (local.get $x)
+    (i32.xor
+     (local.tee $x
+      (i32.const 1)
+     )
+     (local.get $x)
+    )
+   )
+  )
+  (drop
+   (i32.xor
+    (i32.xor
+     (local.get $x)
+     (local.tee $x
+      (i32.const 1)
+     )
+    )
+    (local.get $x)
+   )
+  )
+ )
+ (func $optimize-shifts (param $x i32) (param $y i32) (param $z i64) (param $w i64)
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $z)
+  )
+  (drop
+   (local.get $z)
+  )
+  (drop
+   (local.get $z)
+  )
+  (drop
+   (local.get $z)
+  )
+  (drop
+   (local.get $z)
+  )
+  (drop
+   (i32.shl
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.shl
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.shr_s
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i32.shr_u
+    (local.get $x)
+    (local.get $y)
+   )
+  )
+  (drop
+   (i64.shl
+    (local.get $z)
+    (local.get $w)
+   )
+  )
+  (drop
+   (i64.shl
+    (local.get $z)
+    (local.get $w)
+   )
+  )
+  (drop
+   (i64.shr_s
+    (local.get $z)
+    (local.get $w)
+   )
+  )
+  (drop
+   (i64.shr_u
+    (local.get $z)
+    (local.get $w)
+   )
+  )
+  (drop
+   (local.get $x)
+  )
+  (drop
+   (local.get $z)
+  )
+  (drop
+   (i64.shl
+    (local.get $z)
+    (i64.and
+     (local.get $w)
+     (i64.const 32)
+    )
+   )
+  )
+  (drop
+   (i64.shr_u
+    (local.get $z)
+    (i64.and
+     (local.get $w)
+     (i64.const 31)
+    )
+   )
+  )
+ )
+ (func $optimize-float-points (param $x0 f64) (param $x1 f64) (param $y0 f32) (param $y1 f32)
+  (drop
+   (f64.mul
+    (local.get $x0)
+    (local.get $x0)
+   )
+  )
+  (drop
+   (f32.mul
+    (local.get $y0)
+    (local.get $y0)
+   )
+  )
+  (drop
+   (f64.mul
+    (f64.add
+     (local.get $x0)
+     (local.get $x1)
+    )
+    (f64.add
+     (local.get $x0)
+     (local.get $x1)
+    )
+   )
+  )
+  (drop
+   (f64.abs
+    (f64.mul
+     (local.get $x0)
+     (local.get $x1)
+    )
+   )
+  )
+  (drop
+   (f32.abs
+    (f32.mul
+     (local.get $y1)
+     (local.get $y0)
+    )
+   )
+  )
+  (drop
+   (f64.abs
+    (f64.mul
+     (local.get $x0)
+     (f64.const 0)
+    )
+   )
+  )
+  (drop
+   (f32.abs
+    (f32.mul
+     (f32.const 0)
+     (local.get $y0)
+    )
+   )
+  )
+  (drop
+   (f64.abs
+    (f64.mul
+     (f64.add
+      (local.get $x0)
+      (local.get $x1)
+     )
+     (f64.add
+      (local.get $x0)
+      (local.get $x0)
+     )
+    )
+   )
+  )
+  (drop
+   (f64.abs
+    (local.get $x0)
+   )
+  )
+  (drop
+   (f32.abs
+    (local.get $y0)
+   )
+  )
+  (drop
+   (f64.abs
+    (f64.sub
+     (f64.const 0)
+     (local.get $x0)
+    )
+   )
+  )
+  (drop
+   (f32.abs
+    (f32.sub
+     (f32.const 0)
+     (local.get $y0)
+    )
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $x0)
+    (local.get $x0)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $y0)
+    (local.get $y0)
+   )
+  )
+  (drop
+   (f64.div
+    (f64.add
+     (local.get $x0)
+     (local.get $x1)
+    )
+    (f64.add
+     (local.get $x0)
+     (local.get $x1)
+    )
+   )
+  )
+  (drop
+   (f64.abs
+    (f64.div
+     (local.get $x0)
+     (local.get $x1)
+    )
+   )
+  )
+  (drop
+   (f32.abs
+    (f32.div
+     (local.get $y1)
+     (local.get $y0)
+    )
+   )
+  )
+  (drop
+   (f64.mul
+    (local.get $x0)
+    (local.get $x0)
+   )
+  )
+  (drop
+   (f32.mul
+    (local.get $y0)
+    (local.get $y0)
+   )
+  )
+  (drop
+   (f64.div
+    (local.get $x0)
+    (local.get $x0)
+   )
+  )
+  (drop
+   (f32.div
+    (local.get $y0)
+    (local.get $y0)
+   )
+  )
+  (drop
+   (f64.abs
+    (f64.div
+     (local.get $x0)
+     (f64.const 0)
+    )
+   )
+  )
+  (drop
+   (f32.abs
+    (f32.div
+     (f32.const 0)
+     (local.get $y0)
+    )
+   )
+  )
+  (drop
+   (f64.abs
+    (f64.div
+     (f64.add
+      (local.get $x0)
+      (local.get $x1)
+     )
+     (f64.add
+      (local.get $x0)
+      (local.get $x0)
+     )
+    )
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (import "env" "memory" (memory $0 (shared 256 256)))
+ (func $x
+  (drop
+   (i32.shr_s
+    (i32.shl
+     (i32.atomic.load8_u
+      (i32.const 100)
+     )
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+)
+(module
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (memory $0 0)
+ (func $optimize-bulk-memory-copy (param $dst i32) (param $src i32) (param $sz i32)
+  (memory.copy
+   (local.get $dst)
+   (local.get $dst)
+   (local.get $sz)
+  )
+  (memory.copy
+   (local.get $dst)
+   (local.get $src)
+   (i32.const 0)
+  )
+  (i32.store8
+   (local.get $dst)
+   (i32.load8_u
+    (local.get $src)
+   )
+  )
+  (i32.store16 align=1
+   (local.get $dst)
+   (i32.load16_u align=1
+    (local.get $src)
+   )
+  )
+  (memory.copy
+   (local.get $dst)
+   (local.get $src)
+   (i32.const 3)
+  )
+  (i32.store align=1
+   (local.get $dst)
+   (i32.load align=1
+    (local.get $src)
+   )
+  )
+  (memory.copy
+   (local.get $dst)
+   (local.get $src)
+   (i32.const 5)
+  )
+  (memory.copy
+   (local.get $dst)
+   (local.get $src)
+   (i32.const 6)
+  )
+  (memory.copy
+   (local.get $dst)
+   (local.get $src)
+   (i32.const 7)
+  )
+  (i64.store align=1
+   (local.get $dst)
+   (i64.load align=1
+    (local.get $src)
+   )
+  )
+  (v128.store align=1
+   (local.get $dst)
+   (v128.load align=1
+    (local.get $src)
+   )
+  )
+  (memory.copy
+   (local.get $dst)
+   (local.get $src)
+   (local.get $sz)
+  )
+  (memory.copy
+   (i32.const 0)
+   (i32.const 0)
+   (i32.load
+    (i32.const 3)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_anyref (func (result anyref)))
+ (func $if-arms-subtype-fold (result anyref)
+  (ref.null extern)
+ )
+ (func $if-arms-subtype-nofold (result anyref)
+  (if (result anyref)
+   (i32.const 0)
+   (ref.null extern)
+   (ref.null func)
+  )
+ )
+)
+(module
+ (type $i32_i32_i32_f64_=>_none (func (param i32 i32 i32 f64)))
+ (func $duplicate-elimination (param $x i32) (param $y i32) (param $z i32) (param $w f64)
+  (drop
+   (i32.extend8_s
+    (local.get $x)
+   )
+  )
+  (drop
+   (i32.extend16_s
+    (local.get $x)
+   )
+  )
+ )
+)
+(module
+ (type $none_=>_none (func))
+ (func $test
+  (if
+   (try (result i32)
+    (do
+     (i32.const 123)
+    )
+    (catch
+     (drop
+      (pop exnref)
+     )
+     (i32.const 456)
+    )
+   )
+   (nop)
+  )
+ )
+)
+(module
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32)))
+ (func $call_from-param (param $f (ref null $i32_=>_i32)) (result i32)
+  (unreachable)
  )
 )
diff --git a/binaryen/test/passes/optimize-instructions_all-features.wast b/binaryen/test/passes/optimize-instructions_all-features.wast
--- a/binaryen/test/passes/optimize-instructions_all-features.wast
+++ b/binaryen/test/passes/optimize-instructions_all-features.wast
@@ -2,5175 +2,6186 @@
   (memory 0)
   (type $0 (func (param i32 i64)))
   (func $f (type $0) (param $i1 i32) (param $i2 i64)
-    (if
-      (i32.eqz
-        (local.get $i1)
-      )
-      (drop
-        (i32.const 10)
-      )
-    )
-    (if
-      (i32.eqz
-        (local.get $i1)
-      )
-      (drop
-        (i32.const 11)
-      )
-      (drop
-        (i32.const 12)
-      )
-    )
-    (if
-      (i64.eqz
-        (local.get $i2)
-      )
-      (drop
-        (i32.const 11)
-      )
-      (drop
-        (i32.const 12)
-      )
-    )
-    (drop
-      (i32.eqz
-        (i32.gt_s
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (i32.ge_s
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (i32.lt_s
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (i32.le_s
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (i32.gt_u
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (i32.ge_u
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (i32.lt_u
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (i32.le_u
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f32.gt
-          (f32.const 1)
-          (f32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f32.ge
-          (f32.const 1)
-          (f32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f32.lt
-          (f32.const 1)
-          (f32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f32.le
-          (f32.const 1)
-          (f32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f64.gt
-          (f64.const 1)
-          (f64.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f64.ge
-          (f64.const 1)
-          (f64.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f64.lt
-          (f64.const 1)
-          (f64.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f64.le
-          (f64.const 1)
-          (f64.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f32.eq
-          (f32.const 1)
-          (f32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f32.ne
-          (f32.const 1)
-          (f32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f64.eq
-          (f64.const 1)
-          (f64.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.eqz
-        (f64.ne
-          (f64.const 1)
-          (f64.const 2)
-        )
-      )
-    )
-    ;; we handle only 0 in the right position, as we assume a const is there, and don't care about if
-    ;; both are consts here (precompute does that, so no need)
-    (drop
-      (i32.eq
-        (i32.const 100)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.const 0)
-        (i32.const 100)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.const 0)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i64.eq
-        (i64.const 100)
-        (i64.const 0)
-      )
-    )
-    (drop
-      (i64.eq
-        (i64.const 0)
-        (i64.const 100)
-      )
-    )
-    (drop
-      (i64.eq
-        (i64.const 0)
-        (i64.const 0)
-      )
-    )
-    (if
-      (i32.eqz
-        (i32.eqz
-          (i32.const 123)
-        )
-      )
-      (nop)
-    )
-    (if
-      (try (result i32)
-        (do
-          (i32.eqz
-            (i32.eqz
-              (i32.const 123)
-            )
-          )
-        )
-        (catch
-          (drop
-            (pop exnref)
-          )
-          (i32.eqz
-            (i32.eqz
-              (i32.const 456)
-            )
-          )
-        )
-      )
-      (nop)
-    )
-    (drop
-      (select
-        (i32.const 101)
-        (i32.const 102)
-        (i32.eqz
-          (local.get $i1)
-        )
-      )
-    )
-    (drop
-      (select
-        (local.tee $i1
-          (i32.const 103)
-        ) ;; these conflict
-        (local.tee $i1
-          (i32.const 104)
-        )
-        (i32.eqz
-          (local.get $i1)
-        )
-      )
-    )
-    (drop
-      (select
-        (i32.const 0)
-        (i32.const 1)
-        (i32.eqz
-          (i32.eqz
-            (i32.const 2)
-          )
-        )
-      )
-    )
-  )
-  (func $load-store
-    (drop (i32.and (i32.load8_s (i32.const 0)) (i32.const 255)))
-    (drop (i32.and (i32.load8_u (i32.const 1)) (i32.const 255)))
-    (drop (i32.and (i32.load8_s (i32.const 2)) (i32.const 254)))
-    (drop (i32.and (i32.load8_u (i32.const 3)) (i32.const 1)))
-    (drop (i32.and (i32.load16_s (i32.const 4)) (i32.const 65535)))
-    (drop (i32.and (i32.load16_u (i32.const 5)) (i32.const 65535)))
-    (drop (i32.and (i32.load16_s (i32.const 6)) (i32.const 65534)))
-    (drop (i32.and (i32.load16_u (i32.const 7)) (i32.const 1)))
-    ;;
-    (i32.store8 (i32.const 8) (i32.and (i32.const -1) (i32.const 255)))
-    (i32.store8 (i32.const 9) (i32.and (i32.const -2) (i32.const 254)))
-    (i32.store16 (i32.const 10) (i32.and (i32.const -3) (i32.const 65535)))
-    (i32.store16 (i32.const 11) (i32.and (i32.const -4) (i32.const 65534)))
-    ;;
-    (i32.store8 (i32.const 11) (i32.wrap_i64 (i64.const 1)))
-    (i32.store16 (i32.const 11) (i32.wrap_i64 (i64.const 2)))
-    (i32.store (i32.const 11) (i32.wrap_i64 (i64.const 3)))
-  )
-  (func $and-neg1
-    (drop (i32.and (i32.const 100) (i32.const -1)))
-    (drop (i32.and (i32.const 100) (i32.const  1)))
-  )
-  (func $and-pos1
-    (drop (i32.and (i32.eqz (i32.const 1000)) (i32.const 1)))
-    (drop (i32.and (i32.const 1) (i32.eqz (i32.const 1000))))
-    (drop (i32.and (i32.const 100) (i32.const 1)))
-    (drop (i32.and (i32.lt_s (i32.const 2000) (i32.const 3000)) (i32.const 1)))
-  )
-  (func $canonicalize (param $x i32) (param $y i32) (param $fx f64) (param $fy f64)
-    (drop (i32.and (unreachable) (i32.const 1))) ;; ok to reorder
-    (drop (i32.and (i32.const 1) (unreachable)))
-    (drop (i32.div_s (unreachable) (i32.const 1))) ;; not ok
-    (drop (i32.div_s (i32.const 1) (unreachable)))
-    ;; the various orderings
-    (drop (i32.and (i32.const 1) (i32.const 2)))
-    (drop (i32.and (local.get $x) (i32.const 3)))
-    (drop (i32.and (i32.const 4) (local.get $x)))
-    (drop (i32.and (local.get $x) (local.get $y)))
-    (drop (i32.and (local.get $y) (local.get $x)))
-    (drop (i32.and (local.get $y) (local.tee $x (i32.const -4))))
-    (drop (i32.and
-      (block (result i32)
-        (i32.const -5)
-      )
-      (local.get $x)
-    ))
-    (drop (i32.and
-      (local.get $x)
-      (block (result i32)
-        (i32.const -6)
-      )
-    ))
-    (drop (i32.and
-      (block (result i32)
-        (i32.const 5)
-      )
-      (loop (result i32)
-        (i32.const 6)
-      )
-    ))
-    (drop (i32.and
-      (loop (result i32)
-        (i32.const 7)
-      )
-      (block (result i32)
-        (i32.const 8)
-      )
-    ))
-    (drop (i32.and
-      (loop (result i32)
-        (call $and-pos1)
-        (i32.const 9)
-      )
-      (block (result i32)
-        (i32.const 10)
-      )
-    ))
-    (drop (i32.and
-      (loop (result i32)
-        (i32.const 11)
-      )
-      (block (result i32)
-        (call $and-pos1)
-        (i32.const 12)
-      )
-    ))
-    (drop (i32.and
-      (loop (result i32)
-        (call $and-pos1)
-        (i32.const 13)
-      )
-      (block (result i32)
-        (call $and-pos1)
-        (i32.const 14)
-      )
-    ))
-    (drop (i32.and
-      (block (result i32)
-        (call $and-pos1)
-        (i32.const 14)
-      )
-      (loop (result i32)
-        (call $and-pos1)
-        (i32.const 13)
-      )
-    ))
-    (drop (i32.and
-      (block (result i32)
-        (i32.const 15)
-      )
-      (local.get $x)
-    ))
-    (drop (i32.and
-      (local.get $x)
-      (block (result i32)
-        (i32.const 15)
-      )
-    ))
-    (drop (i32.and
-      (i32.gt_s
-        (i32.const 16)
-        (i32.const 17)
-      )
-      (i32.gt_u
-        (i32.const 18)
-        (i32.const 19)
-      )
-    ))
-    (drop (i32.and
-      (i32.gt_u
-        (i32.const 20)
-        (i32.const 21)
-      )
-      (i32.gt_s
-        (i32.const 22)
-        (i32.const 23)
-      )
-    ))
-    (drop (i32.add (i32.ctz (local.get $x)) (i32.ctz (local.get $y))))
-    (drop (i32.add (i32.ctz (local.get $y)) (i32.ctz (local.get $x))))
-    (drop (i32.add (i32.ctz (local.get $x)) (i32.eqz (local.get $y))))
-    (drop (i32.add (i32.eqz (local.get $x)) (i32.ctz (local.get $y))))
-  )
-  (func $ne0 (result i32)
-    (if (i32.ne (call $ne0) (i32.const 0))
-      (nop)
-    )
-    (if (i32.ne (i32.const 0) (call $ne0))
-      (nop)
-    )
-    ;; through an or
-    (if
-      (i32.or
-        (i32.ne (i32.const 0) (call $ne0))
-        (i32.ne (i32.const 0) (call $ne0))
-      )
-      (nop)
-    )
-    ;; but not an and
-    (if
-      (i32.and
-        (i32.ne (i32.const 0) (call $ne0))
-        (i32.ne (i32.const 0) (call $ne0))
-      )
-      (nop)
-    )
-    (i32.const 1)
-  )
-  (func $recurse-bool
-    (if
-      (if (result i32)
-        (i32.const 1)
-        (i32.ne (call $ne0) (i32.const 0))
-        (i32.ne (call $ne1) (i32.const 0))
-      )
-      (nop)
-    )
-    (if
-      (block (result i32)
-        (nop)
-        (i32.ne (call $ne0) (i32.const 0))
-      )
-      (nop)
-    )
-  )
-  (func $ne1 (result i32)
-    (unreachable)
-  )
-  (func $load-off-2 "load-off-2" (param $0 i32) (result i32)
-    (i32.store offset=2
-      (i32.add
-        (i32.const 1)
-        (i32.const 3)
-      )
-      (local.get $0)
-    )
-    (i32.store offset=2
-      (i32.add
-        (i32.const 3)
-        (i32.const 1)
-      )
-      (local.get $0)
-    )
-    (i32.store offset=2
-      (i32.add
-        (local.get $0)
-        (i32.const 5)
-      )
-      (local.get $0)
-    )
-    (i32.store offset=2
-      (i32.add
-        (i32.const 7)
-        (local.get $0)
-      )
-      (local.get $0)
-    )
-    (i32.store offset=2
-      (i32.add
-        (i32.const -11) ;; do not fold this!
-        (local.get $0)
-      )
-      (local.get $0)
-    )
-    (i32.store offset=2
-      (i32.add
-        (local.get $0)
-        (i32.const -13) ;; do not fold this!
-      )
-      (local.get $0)
-    )
-    (i32.store offset=2
-      (i32.add
-        (i32.const -15)
-        (i32.const 17)
-      )
-      (local.get $0)
-    )
-    (i32.store offset=2
-      (i32.add
-        (i32.const -21)
-        (i32.const 19)
-      )
-      (local.get $0)
-    )
-    (i32.store offset=2
-      (i32.const 23)
-      (local.get $0)
-    )
-    (i32.store offset=2
-      (i32.const -25)
-      (local.get $0)
-    )
-    (drop
-      (i32.load offset=2
-        (i32.add
-          (i32.const 2)
-          (i32.const 4)
-        )
-      )
-    )
-    (drop
-      (i32.load offset=2
-        (i32.add
-          (i32.const 4)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.load offset=2
-        (i32.add
-          (local.get $0)
-          (i32.const 6)
-        )
-      )
-    )
-    (drop
-      (i32.load offset=2
-        (i32.const 8)
-      )
-    )
-    (i32.load offset=2
-      (i32.add
-        (i32.const 10)
-        (local.get $0)
-      )
-    )
-  )
-  (func $sign-ext (param $0 i32) (param $1 i32)
-    ;; eq of sign-ext to const, can be a zext
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 16)
-          )
-          (i32.const 16)
-        )
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 5) ;; weird size, but still valid
-          )
-          (i32.const 5)
-        )
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 100) ;; non-zero
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 32767) ;; non-zero and bigger than the mask, with sign bit
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const -149) ;; non-zero and bigger than the mask, without sign bit
-      )
-    )
-    ;; eq of two sign-ext, can both be a zext
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.shr_s
-          (i32.shl
-            (local.get $1)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 16)
-          )
-          (i32.const 16)
-        )
-        (i32.shr_s
-          (i32.shl
-            (local.get $1)
-            (i32.const 16)
-          )
-          (i32.const 16)
-        )
-      )
-    )
-    ;; corner cases we should not opt
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 23) ;; different shift, smaller
-        )
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_u ;; unsigned
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.lt_s ;; non-eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 0)
-      )
-    )
-  )
-  (func $sign-ext-input (param $0 i32) (param $1 i32)
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.const 100) ;; small!
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.const 127) ;; just small enough
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.const 128) ;; just too big
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $0) ;; who knows...
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (unreachable) ;; ignore
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.div_s ;; this could be optimizable in theory, but currently we don't look into adds etc.
-            (i32.const 1)
-            (i32.const 2)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.and ;; takes the min, here it is ok
-            (i32.const 127)
-            (i32.const 128)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.and ;; takes the min, here it is not
-            (i32.const 128)
-            (i32.const 129)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.xor ;; takes the max, here it is ok
-            (i32.const 127)
-            (i32.const 126)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.xor ;; takes the max, here it is not
-            (i32.const 127)
-            (i32.const 128)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.or ;; takes the max, here it is ok
-            (i32.const 127)
-            (i32.const 126)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.or ;; takes the max, here it is not
-            (i32.const 127)
-            (i32.const 128)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shl ;; adds, here it is too much
-            (i32.const 32)
-            (i32.const 2)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shl ;; adds, here it is ok
-            (i32.const 32)
-            (i32.const 1)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shl ;; adds, here it is too much and "overflows"
-            (i32.const 32)
-            (i32.const 35)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_u ;; subtracts, here it is still too much
-            (i32.const 256)
-            (i32.const 1)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_u ;; subtracts, here it is ok
-            (i32.const 256)
-            (i32.const 2)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_u ;; subtracts, here it "overflows"
-            (i32.const 128)
-            (i32.const 35)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_s ;; subtracts, here it is still too much
-            (i32.const 256)
-            (i32.const 1)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_s ;; subtracts, here it is ok
-            (i32.const 256)
-            (i32.const 2)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_s ;; subtracts, here it "overflows"
-            (i32.const 128)
-            (i32.const 35)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_s ;; subtracts, here there is a sign bit, so it stays 32 bits no matter how much we shift
-            (i32.const -1)
-            (i32.const 32)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_s ;; subtracts, here we mask out that sign bit
-            (i32.and
-              (i32.const -1)
-              (i32.const 2147483647)
-            )
-            (i32.const 31) ;; adjusted after we fixed shift computation to just look at lower 5 bits
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.ne ;; 1 bit
-            (i32.const -1)
-            (i32.const -1)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (f32.le
-            (f32.const -1)
-            (f32.const -1)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.clz ;; assumed 5 bits
-            (i32.const 0)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shl
-            (i32.clz ;; assumed 5 bits
-              (i32.const 0)
-            )
-            (i32.const 2) ;; + 2, so 7
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shl
-            (i32.clz ;; assumed 5 bits
-              (i32.const 0)
-            )
-            (i32.const 3) ;; + 3, so 8, too much
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.wrap_i64 ;; preserves 6
-            (i64.clz ;; assumed 6 bits
-              (i64.const 0)
-            )
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shl
-            (i32.wrap_i64 ;; preserves 6
-              (i64.clz ;; assumed 6 bits
-                (i64.const 0)
-              )
-            )
-            (i32.const 1) ;; + 1, so 7
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shl
-            (i32.wrap_i64 ;; preserves 6
-              (i64.clz ;; assumed 6 bits
-                (i64.const 0)
-              )
-            )
-            (i32.const 2) ;; + 2, so 8, too much
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.eqz ;; 1 bit
-            (i32.const -1)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_u
-            (i32.wrap_i64 ;; down to 32
-              (i64.const -1) ;; 64
-            )
-            (i32.const 24) ;; 32 - 24 = 8
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_u
-            (i32.wrap_i64 ;; down to 32
-              (i64.const -1) ;; 64
-            )
-            (i32.const 25) ;; 32 - 25 = 7, ok
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_u
-            (i32.wrap_i64 ;; stay 32
-              (i64.extend_i32_s
-                (i32.const -1)
-              )
-            )
-            (i32.const 24) ;; 32 - 24 = 8
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_u
-            (i32.wrap_i64 ;; stay 32
-              (i64.extend_i32_s
-                (i32.const -1)
-              )
-            )
-            (i32.const 25) ;; 32 - 25 = 7, ok
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop ;; fuzz testcase
-      (i32.shr_s
-        (i32.shl
-          (i32.xor ;; should be 32 bits
-            (i32.le_u ;; 1 bit
-              (local.get $0)
-              (i32.const 2)
-            )
-            (local.get $0) ;; unknown, so 32 bits
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-  )
-  (func $linear-sums (param $0 i32) (param $1 i32)
-    (drop
-      (i32.add
-        (i32.add
-          (local.get $1)
-          (i32.const 16)
-        )
-        (i32.shl
-          (i32.add
-            (local.get $0)
-            (i32.const -1) ;; -16, so cancels out!
-          )
-          (i32.const 4)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.add
-          (local.get $1)
-          (i32.const 20)
-        )
-        (i32.shl
-          (i32.add
-            (local.get $0)
-            (i32.const -1) ;; -8, so sum is +12
-          )
-          (i32.const 3)
-        )
-      )
-    )
-    (drop
-      (i32.add ;; simple sum
-        (i32.const 1)
-        (i32.const 3)
-      )
-    )
-    (drop
-      (i32.add ;; nested sum
-        (i32.add
-          (i32.const 1)
-          (i32.const 3)
-        )
-        (i32.add
-          (i32.const 5)
-          (i32.const 9)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.add
-          (i32.const 1)
-          (i32.const 3)
-        )
-        (i32.sub ;; internal sub
-          (i32.const 5)
-          (i32.const 3)
-        )
-      )
-    )
-    (drop
-      (i32.sub ;; external sub
-        (i32.add
-          (i32.const 1)
-          (i32.const 3)
-        )
-        (i32.add
-          (i32.const 5)
-          (i32.const 3)
-        )
-      )
-    )
-    (drop
-      (i32.sub ;; external sub
-        (i32.add
-          (i32.const 1)
-          (i32.const 3)
-        )
-        (i32.sub ;; and also internal sub
-          (i32.const 5)
-          (i32.const 3)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.add
-          (i32.const 1)
-          (i32.const 3)
-        )
-        (i32.sub ;; negating sub
-          (i32.const 0)
-          (i32.const 3)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.sub
-          (i32.const 0)
-          (i32.sub ;; two negating subs
-            (i32.const 0)
-            (i32.add
-              (i32.const 3)
-              (i32.const 20)
-            )
-          )
-        )
-        (i32.add
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.add
-          (i32.const 0)
-          (i32.sub ;; one negating sub
-            (i32.const 0)
-            (i32.add
-              (i32.const 3)
-              (i32.const 20)
-            )
-          )
-        )
-        (i32.add
-          (i32.const 1)
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.shl ;; shifted value
-          (i32.const 1)
-          (i32.const 3)
-        )
-        (i32.add
-          (i32.const 5)
-          (i32.const 9)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.shl ;; shifted value
-          (i32.const 1)
-          (local.get $0) ;; but not by const
-        )
-        (i32.add
-          (i32.const 5)
-          (i32.const 9)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.shl ;; shifted nested value
-          (i32.sub
-            (local.get $1)
-            (i32.const 10)
-          )
-          (i32.const 3)
-        )
-        (i32.add
-          (i32.const 5)
-          (i32.const 9)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.mul ;; multiplied
-          (i32.const 10)
-          (i32.const 3)
-        )
-        (i32.add
-          (i32.const 5)
-          (i32.const 9)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.mul ;; multiplied by nonconstant - can't recurse
-          (i32.const 10)
-          (local.get $0)
-        )
-        (i32.add
-          (i32.const 5)
-          (i32.const 9)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.mul ;; nested mul
-          (i32.add
-            (i32.const 10)
-            (local.get $0)
-          )
-          (i32.const 2)
-        )
-        (i32.add
-          (i32.const 5)
-          (i32.const 9)
-        )
-      )
-    )
-    (drop
-      (i32.add
-        (i32.add
-          (local.get $0)
-          (i32.const 10) ;; cancelled out with the below
-        )
-        (i32.sub
-          (i32.const -5)
-          (i32.const 5)
-        )
-      )
-    )
-  )
-  (func $almost-sign-ext (param $0 i32)
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.const 100) ;; too big, there is a sign bit, due to the extra shift
-          (i32.const 25)
-        )
-        (i32.const 24) ;; different shift, but larger, so ok to opt if we leave a shift, in theory
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.const 50) ;; small enough, no sign bit
-          (i32.const 25)
-        )
-        (i32.const 24) ;; different shift, but larger, so ok to opt if we leave a shift
-      )
-    )
-  )
-  (func $squaring (param $0 i32) (param $1 i32)
-    (drop
-      (i32.and
-        (i32.and
-          (local.get $0)
-          (i32.const 11)
-        )
-        (i32.const 200)
-      )
-    )
-    (drop
-      (i32.and
-        (i32.and
-          (local.get $0)
-          (i32.const 11)
-        )
-        (local.get $0) ;; non-const, cannot optimize this!
-      )
-    )
-    (drop
-      (i32.and
-        (i32.and
-          (i32.const 11) ;; flipped order
-          (local.get $0)
-        )
-        (i32.const 200)
-      )
-    )
-    (drop
-      (i32.or
-        (i32.or
-          (local.get $0)
-          (i32.const 11)
-        )
-        (i32.const 200)
-      )
-    )
-    (drop
-      (i32.shl
-        (i32.shl
-          (local.get $0)
-          (i32.const 11)
-        )
-        (i32.const 200)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shr_s
-          (local.get $0)
-          (i32.const 11)
-        )
-        (i32.const 200)
-      )
-    )
-    (drop
-      (i32.shr_u
-        (i32.shr_u
-          (local.get $0)
-          (i32.const 11)
-        )
-        (i32.const 200)
-      )
-    )
-    (drop
-      (i32.shr_u
-        (i32.shr_s ;; but do not optimize a mixture or different shifts!
-          (local.get $0)
-          (i32.const 11)
-        )
-        (i32.const 200)
-      )
-    )
-  )
-  (func $sign-ext-ne (param $0 i32) (param $1 i32)
-    ;; ne of sign-ext to const, can be a zext
-    (drop
-      (i32.ne
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 65000)
-      )
-    )
-    (drop
-      (i32.ne
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 64872) ;; no sign bit
-      )
-    )
-    (drop
-      (i32.ne
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const -149) ;; no sign bit, not all ones
-      )
-    )
-    (drop
-      (i32.ne
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 111)
-      )
-    )
-    (drop
-      (i32.ne
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.shr_s
-          (i32.shl
-            (local.get $1)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-      )
-    )
-  )
-  (func $sign-ext-eqz (param $0 i32) (param $1 i32)
-    (drop
-      (i32.eqz
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-      )
-    )
-  )
-  (func $sign-ext-boolean (param $0 i32) (param $1 i32)
-    (drop
-      (if (result i32)
-        (i32.shr_s
-          (i32.shl
-            (local.get $0)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 100)
-        (i32.const 200)
-      )
-    )
-  )
-  (func $add-sub-zero (param $0 i32) (param $1 i32)
-    (drop
-      (i32.add
-        (local.get $0)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.sub
-        (local.get $0)
-        (i32.const 0)
-      )
-    )
-  )
-  (func $store-signext (param $0 i32)
-    (i32.store8
-      (i32.const 8)
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 24) ;; exact size we store, sign-ext of 8 bits
-        )
-        (i32.const 24)
-      )
-    )
-    (i32.store8
-      (i32.const 8)
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 25) ;; 7 bits. so the ext can alter a bit we store, do not optimize
-        )
-        (i32.const 25)
-      )
-    )
-    (i32.store8
-      (i32.const 8)
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 23) ;; 9 bits, this is good to optimize
-        )
-        (i32.const 23)
-      )
-    )
-    (i32.store16
-      (i32.const 8)
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 16) ;; exact size we store, sign-ext of 16 bits
-        )
-        (i32.const 16)
-      )
-    )
-    (i32.store16
-      (i32.const 8)
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 17) ;; 15 bits. so the ext can alter a bit we store, do not optimize
-        )
-        (i32.const 17)
-      )
-    )
-    (i32.store16
-      (i32.const 8)
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 14) ;; 17 bits, this is good to optimize
-        )
-        (i32.const 14)
-      )
-    )
-    (i32.store
-      (i32.const 8)
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 16) ;; 4 bytes stored, do nothing
-        )
-        (i32.const 16)
-      )
-    )
-    (i32.store
-      (i32.const 8)
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 8) ;; 4 bytes stored, do nothing
-        )
-        (i32.const 8)
-      )
-    )
-  )
-  (func $sign-ext-tee (param $0 i32) (param $1 i32)
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.tee $0
-            (i32.const 128) ;; too big
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.tee $0
-            (i32.const 127) ;; just right
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-  )
-  (func $sign-ext-load (param $0 i32) (param $1 i32)
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.load8_s ;; one byte, so perfect
-            (i32.const 256)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_u
-            (i32.load8_s ;; one byte, but sexted to 32
-              (i32.const 256)
-            )
-            (i32.const 1)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shr_u
-            (i32.load8_u ;; one byte, but reduced to 7
-              (i32.const 256)
-            )
-            (i32.const 1)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.load16_s ;; two, so perfect
-            (i32.const 256)
-          )
-          (i32.const 16)
-        )
-        (i32.const 16)
-      )
-    )
-    ;; through tees, we cannot alter the load sign
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.tee $1
-            (i32.load8_s
-              (i32.const 1)
-            )
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.tee $1
-            (i32.load8_u
-              (i32.const 1)
-            )
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.and
-        (local.tee $1
-          (i32.load8_s
-            (i32.const 1)
-          )
-        )
-        (i32.const 255)
-      )
-    )
-    (drop
-      (i32.and
-        (local.tee $1
-          (i32.load8_u
-            (i32.const 1)
-          )
-        )
-        (i32.const 255)
-      )
-    )
-  )
-  (func $mask-bits (param $0 i32) (param $1 i32)
-    (drop
-      (i32.and
-        (local.tee $0
-          (i32.const 127) ;; 7 bits
-        )
-        (i32.const 255) ;; mask 8, so we don't need this
-      )
-    )
-    (drop
-      (i32.and
-        (local.tee $0
-          (i32.const 128) ;; 8 bits
-        )
-        (i32.const 255) ;; mask 8, so we don't need this
-      )
-    )
-    (drop
-      (i32.and
-        (local.tee $0
-          (i32.const 128)
-        )
-        (i32.const 254) ;; improper mask, small
-      )
-    )
-    (drop
-      (i32.and
-        (local.tee $0
-          (i32.const 128)
-        )
-        (i32.const 1279) ;; improper mask, large
-      )
-    )
-    (drop
-      (i32.and
-        (local.tee $0
-          (i32.const 128)
-        )
-        (i32.const 1290) ;; improper mask, large
-      )
-    )
-    (drop
-      (i32.and
-        (local.tee $0
-          (i32.const 128)
-        )
-        (i32.const 4095) ;; proper mask, huge
-      )
-    )
-    (drop
-      (i32.and
-        (local.tee $0
-          (i32.const 128)
-        )
-        (i32.const 511) ;; proper mask, large
-      )
-    )
-    (drop
-      (i32.and
-        (local.tee $0
-          (i32.const 128)
-        )
-        (i32.const 127) ;; proper mask, just too small
-      )
-    )
-  )
-  (func $local-info-zero-ext (param $0 i32) (param $1 i32)
-    (local $x i32)
-    (local $y i32)
-    (local $z i32)
-    (local $w i32)
-    (local.set $x
-      (i32.const 212) ;; mask is unneeded, we are small
-    )
-    (drop
-      (i32.and
-        (local.get $x)
-        (i32.const 255)
-      )
-    )
-    (local.set $y
-      (i32.const 500) ;; mask is needed, we are too big
-    )
-    (drop
-      (i32.and
-        (local.get $y)
-        (i32.const 255)
-      )
-    )
-    (local.set $0
-      (i32.const 212) ;; mask is unneeded, but we are a param, not a var, so no
-    )
-    (drop
-      (i32.and
-        (local.get $0)
-        (i32.const 255)
-      )
-    )
-    (local.set $z
-      (i32.const 212) ;; mask is unneeded, we are small
-    )
-    (local.set $z
-      (i32.const 220) ;; mask is still unneeded even with 2 uses
-    )
-    (drop
-      (i32.and
-        (local.get $z)
-        (i32.const 255)
-      )
-    )
-    (local.set $w
-      (i32.const 212) ;; mask is unneeded, we are small
-    )
-    (local.set $w
-      (i32.const 1000) ;; mask is needed, one use is too big
-    )
-    (drop
-      (i32.and
-        (local.get $w)
-        (i32.const 255)
-      )
-    )
-  )
-  (func $local-info-sign-ext-bitsize (param $0 i32) (param $1 i32)
-    (local $x i32)
-    (local $y i32)
-    (local $z i32)
-    (local $w i32)
-    (local.set $x
-      (i32.const 127) ;; mask is unneeded, we are small
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $x)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $y
-      (i32.const 128) ;; mask is needed, we are too big
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $y)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $0
-      (i32.const 127) ;; mask is unneeded, but we are a param, not a var, so no
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $z
-      (i32.const 127) ;; mask is unneeded, we are small
-    )
-    (local.set $z
-      (i32.const 100) ;; mask is still unneeded even with 2 uses
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $z)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $w
-      (i32.const 127) ;; mask is unneeded, we are small
-    )
-    (local.set $w
-      (i32.const 150) ;; mask is needed, one use is too big
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $w)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-  )
-  (func $local-info-sign-ext-already-exted (param $0 i32) (param $1 i32)
-    (local $x i32)
-    (local $y i32)
-    (local $z i32)
-    (local $w i32)
-    (local.set $x
-      (i32.shr_s
-        (i32.shl
-          (local.get $0) ;; already sign-exted here, so no need later
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $x)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $y
-      (i32.shr_s
-        (i32.shl
-          (local.get $0) ;; already sign-exted here, but wrong bit size
-          (i32.const 16)
-        )
-        (i32.const 16)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $y)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $0
-      (i32.shr_s
-        (i32.shl
-          (local.get $0) ;; already sign-exted here, so no need later, but we are a param
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $0)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $z
-      (i32.shr_s
-        (i32.shl
-          (local.get $0) ;; already sign-exted here, so no need later
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $z
-      (i32.shr_s
-        (i32.shl
-          (local.get $1) ;; already sign-exted here, so no need later
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $z)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $w
-      (i32.shr_s
-        (i32.shl
-          (local.get $0) ;; already sign-exted here, so no need later
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $w
-      (i32.shr_s
-        (i32.shl
-          (local.get $0) ;; not quite a sign-ext
-          (i32.const 23)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $w)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (drop ;; odd corner case
-      (i32.shr_s
-        (i32.shl
-          (local.get $0) ;; param, so we should know nothing
-          (i32.const 24)
-        )
-        (i32.const 23) ;; different shift, smaller
-      )
-    )
-  )
-  (func $signed-loads-fill-the-bits (param $$e i32) (result i32)
-    (local $$0 i32)
-    (local $$conv i32)
-    (local.set $$0
-      (i32.load8_s ;; one byte, but 32 bits due to sign-extend
-        (i32.const 1024)
-      )
-    )
-    (local.set $$conv
-      (i32.and
-        (local.get $$0)
-        (i32.const 255) ;; so we need this zexting!
-      )
-    )
-    (return
-      (i32.eq
-        (local.get $$conv)
-        (local.get $$e)
-      )
-    )
-  )
-  (func $local-info-sign-ext-already-exted-by-load (param $0 i32) (param $1 i32)
-    (local $x i32)
-    (local $y i32)
-    (local $z i32)
-    (local $w i32)
-    (local.set $x
-      (i32.load8_s (i32.const 1024)) ;; 8 bits, sign extended, no need to do it again
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $x)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $y
-      (i32.load8_u (i32.const 1024)) ;; 8 bits, zext, so bad
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $y)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-    (local.set $z
-      (i32.load16_s (i32.const 1024)) ;; 16 bits sign-extended, wrong size
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (local.get $z)
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-  )
-  (func $compare-load-s-sign-extend (param $0 i32) (param $1 i32)
-    (drop
-      (i32.eq
-        (i32.load8_s
-          (local.get $0)
-        )
-        (i32.shr_s
-          (i32.shl
-            (local.get $1)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $1)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.load8_s
-          (local.get $0) ;; flip order, we should canonicalize
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.load8_u ;; unsigned, bad
-          (local.get $0)
-        )
-        (i32.shr_s
-          (i32.shl
-            (local.get $1)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.load8_s
-          (local.get $0)
-        )
-        (i32.shr_s
-          (i32.shl
-            (local.get $1)
-            (i32.const 16) ;; wrong size
-          )
-          (i32.const 16)
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $1)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.load8_u ;; unsigned, bad
-          (local.get $0)
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $1)
-            (i32.const 16) ;; wrong size
-          )
-          (i32.const 16)
-        )
-        (i32.load8_s
-          (local.get $0)
-        )
-      )
-    )
-  )
-  (func $unsign-diff-sizes (param $x i32) (param $y i32) (result i32)
-    (i32.ne
-      (i32.shr_s
-        (i32.shl
-          (call $unsign-diff-sizes
-            (i32.const -1)
-            (i32.const 5)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-      (i32.shr_s
-        (i32.shl
-          (call $unsign-diff-sizes
-            (i32.const 1)
-            (i32.const 2006)
-          )
-          (i32.const 16)
-        )
-        (i32.const 16)
-      )
-    )
-  )
-  (func $unsign-same-sizes (param $x i32) (param $y i32) (result i32)
-    (i32.ne
-      (i32.shr_s
-        (i32.shl
-          (call $unsign-same-sizes
-            (i32.const -1)
-            (i32.const 5)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-      (i32.shr_s
-        (i32.shl
-          (call $unsign-same-sizes
-            (i32.const 1)
-            (i32.const 2006)
-          )
-          (i32.const 24)
-        )
-        (i32.const 24)
-      )
-    )
-  )
-  (func $fuzz-almost-sign-ext
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.load16_u
-            (i32.const 2278)
-          )
-          (i32.const 17)
-        )
-        (i32.const 16)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.shl
-          (i32.shl
-            (i32.load16_u
-              (i32.const 2278)
-            )
-            (i32.const 1)
-          )
-          (i32.const 16)
-        )
-        (i32.const 16)
-      )
-    )
-  )
-  (func $fuzz-comp-impossible (param $x i32)
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $x)
-            (i32.const 16)
-          )
-          (i32.const 16)
-        )
-        (i32.const 65535) ;; impossible to be equal, the effective sign bit is set, but not the higher bits, which the sign-ext will set on the non-const value
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $x)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 255)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $x)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 127) ;; safe
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $x)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 128) ;; unsafe again
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $x)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 4223) ;; more big bits, so sign bit though
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $x)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const 4224) ;; more big bits
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.shr_s
-          (i32.shl
-            (local.get $x)
-            (i32.const 24)
-          )
-          (i32.const 24)
-        )
-        (i32.const -4) ;; safe even with more big bits, as they are all 1s
-      )
-    )
-  )
-  (func $if-parallel (param $0 i32) (param $1 i32)
-    (drop
-      (if (result i32)
-        (local.get $0)
-        (i32.add (local.get $1) (i32.const 1))
-        (i32.add (local.get $1) (i32.const 1))
-      )
-    )
-    (drop
-      (if (result i32)
-        (local.tee $0 (local.get $1)) ;; side effects!
-        (i32.add (local.get $1) (i32.const 1))
-        (i32.add (local.get $1) (i32.const 1))
-      )
-    )
-    (drop
-      (if (result i32)
-        (local.get $0)
-        (i32.add (local.get $1) (unreachable)) ;; folding them would change the type of the if
-        (i32.add (local.get $1) (unreachable))
-      )
-    )
-    (drop
-      (if (result i32)
-        (local.tee $0 (local.get $1)) ;; side effects!
-        (i32.add (local.get $1) (unreachable)) ;; folding them would change the type of the if
-        (i32.add (local.get $1) (unreachable))
-      )
-    )
-    (drop
-      (if (result i32)
-        (unreachable) ;; !!!
-        (i32.add (local.get $1) (unreachable)) ;; folding them would change the type of the if
-        (i32.add (local.get $1) (unreachable))
-      )
-    )
-  )
-  (func $select-parallel (param $0 i32) (param $1 i32)
-    (drop
-      (select
-        (i32.add (local.get $1) (i32.const 1))
-        (i32.add (local.get $1) (i32.const 1))
-        (local.get $0)
-      )
-    )
-    (drop
-      (select
-        (local.tee $0 (local.get $1)) ;; side effects!
-        (local.tee $0 (local.get $1)) ;; side effects!
-        (local.get $0)
-      )
-    )
-    (drop
-      (select
-        (i32.add (local.get $1) (i32.const 1))
-        (i32.add (local.get $1) (i32.const 1))
-        (local.tee $0 (local.get $1)) ;; side effects! (but no interference with values)
-      )
-    )
-    (drop
-      (select
-        (local.tee $0 (local.get $1)) ;; side effects! interference!
-        (local.tee $0 (local.get $1)) ;; side effects! interference!
-        (local.tee $0 (local.get $1)) ;; side effects! interference!
-      )
-    )
-    (drop
-      (select
-        (local.tee $0 (local.get $1)) ;; side effects!
-        (local.tee $0 (local.get $1)) ;; side effects!
-        (unreachable) ;; side effects! (but no interference with values)
-      )
-    )
-  )
-  (func $zero-shifts-is-not-sign-ext
-   (drop
-    (i32.eq
-     (i32.const -5431187)
-     (i32.add
-      (i32.const 0)
-      (i32.shr_s
-       (i32.shl
-        (i32.load16_s align=1
-         (i32.const 790656516)
-        )
-        (i32.const 0)
-       )
-       (i32.const 0)
-      )
-     )
-    )
-   )
-   (drop
-    (i32.eq
-     (i32.const -5431187)
-     (i32.add
-      (i32.const 0)
-      (i32.shr_s
-       (i32.shl
-        (i32.load16_s align=1
-         (i32.const 790656516)
-        )
-        (i32.const 1)
-       )
-       (i32.const 0)
-      )
-     )
-    )
-   )
-  )
-  (func $zero-ops (result i32)
-   (return
-    (i32.eq
-     (i32.const -1337)
-     (i32.shr_u
-      (i32.add
-       (i32.const 0)
-       (i32.shr_s
-        (i32.shl
-         (i32.load16_s align=1
-          (i32.const 790656516)
-         )
-         (i32.const 0)
-        )
-        (i32.const 0)
-       )
-      )
-      (i32.const 0)
-     )
-    )
-   )
-  )
-  (func $sign-ext-1-and-ne (result i32)
-   (select
-    (i32.ne
-     (i32.const 1333788672)
-     (i32.shr_s
-      (i32.shl
-       (call $sign-ext-1-and-ne)
-       (i32.const 1)
-      )
-      (i32.const 1)
-     )
-    )
-    (i32.const 2)
-    (i32.const 1)
-   )
-  )
-  (func $neg-shifts-and-255 (result i32)
-    (i32.and
-     (i32.shr_u
-      (i32.const -99)
-      (i32.const -32) ;; this shift does nothing
-     )
-     (i32.const 255)
-    )
-  )
-  (func $neg-shifts-and-255-b (result i32)
-   (i32.and
-    (i32.shl
-     (i32.const -2349025)
-     (i32.const -32) ;; this shift does nothing
-    )
-    (i32.const 255)
-   )
-  )
-  (func $shifts-square-overflow (param $x i32) (result i32)
-   (i32.shr_u
-    (i32.shr_u
-     (local.get $x)
-     (i32.const 65535) ;; 31 bits effectively
-    )
-    (i32.const 32767) ;; also 31 bits, so two shifts that force the value into nothing for sure
-   )
-  )
-  (func $shifts-square-no-overflow-small (param $x i32) (result i32)
-   (i32.shr_u
-    (i32.shr_u
-     (local.get $x)
-     (i32.const 1031) ;; 7 bits effectively
-    )
-    (i32.const 4098) ;; 2 bits effectively
-   )
-  )
-  (func $shifts-square-overflow-64 (param $x i64) (result i64)
-   (i64.shr_u
-    (i64.shr_u
-     (local.get $x)
-     (i64.const 65535) ;; 63 bits effectively
-    )
-    (i64.const 64767) ;; also 63 bits, so two shifts that force the value into nothing for sure
-   )
-  )
-  (func $shifts-square-no-overflow-small-64 (param $x i64) (result i64)
-   (i64.shr_u
-    (i64.shr_u
-     (local.get $x)
-     (i64.const 1031) ;; 7 bits effectively
-    )
-    (i64.const 4098) ;; 2 bits effectively
-   )
-  )
-  (func $shifts-square-unreachable (param $x i32) (result i32)
-   (i32.shr_u
-    (i32.shr_u
-     (unreachable)
-     (i32.const 1031) ;; 7 bits effectively
-    )
-    (i32.const 4098) ;; 2 bits effectively
-   )
-  )
-  (func $mix-shifts (result i32)
-    (i32.shr_s
-     (i32.shl
-      (i32.const 23)
-      (i32.const -61)
-     )
-     (i32.const 168)
-    )
-  )
-  (func $actually-no-shifts (result i32)
-    (i32.add
-      (i32.shl
-        (i32.const 23)
-        (i32.const 32) ;; really 0
-      )
-      (i32.const 10)
-    )
-  )
-  (func $less-shifts-than-it-seems (param $x i32) (result i32)
-    (i32.add
-      (i32.shl
-        (i32.const 200)
-        (i32.const 36) ;; really 4
-      )
-      (i32.shl
-        (i32.const 100)
-        (i32.const 4)
-      )
-    )
-  )
-  (func $and-popcount32 (result i32)
-    (i32.and
-      (i32.popcnt
-        (i32.const -1)
-      )
-      (i32.const 31)
-    )
-  )
-  (func $and-popcount32-big (result i32)
-    (i32.and
-      (i32.popcnt
-        (i32.const -1)
-      )
-      (i32.const 63)
-    )
-  )
-  (func $and-popcount64 (result i64) ;; these are TODOs
-    (i64.and
-      (i64.popcnt
-        (i64.const -1)
-      )
-      (i64.const 63)
-    )
-  )
-  (func $and-popcount64-big (result i64)
-    (i64.and
-      (i64.popcnt
-        (i64.const -1)
-      )
-      (i64.const 127)
-    )
-  )
-  (func $and-popcount64-bigger (result i64)
-    (i64.and
-      (i64.popcnt
-        (i64.const -1)
-      )
-      (i64.const 255)
-    )
-  )
-  (func $optimizeAddedConstants-filters-through-nonzero (result i32)
-   (i32.sub
-    (i32.add
-     (i32.shl
-      (i32.const -536870912)
-      (i32.wrap_i64
-       (i64.const 0)
-      )
-     )
-     (i32.const -32768)
-    )
-    (i32.const -1024)
-   )
-  )
-  (func $optimizeAddedConstants-filters-through-nonzero-b (result i32)
-   (i32.sub
-    (i32.add
-     (i32.shl
-      (i32.const -536870912)
-      (i32.wrap_i64
-       (i64.const -1)
-      )
-     )
-     (i32.const -32768)
-    )
-    (i32.const -1024)
-   )
-  )
-  (func $return-proper-value-from-shift-left-by-zero (result i32)
-   (if (result i32)
-    (i32.sub
-     (i32.add
-      (loop $label$0 (result i32)
-       (block $label$1
-        (br_if $label$1
-         (i32.shl
-          (i32.load
-           (i32.const 0)
-          )
-          (i32.const -31904) ;; really 0 shifts
-         )
-        )
-       )
-       (i32.const -62)
-      )
-      (i32.const 38)
-     )
-     (i32.const -2)
-    )
-    (i32.const 1)
-    (i32.const 0)
-   )
-  )
-  (func $de-morgan-2 (param $x i32) (param $y i32)
-    (drop
-      (i32.and (i32.eqz (local.get $x)) (i32.eqz (local.get $y)))
-    )
-    (drop
-      (i32.or (i32.eqz (local.get $x)) (i32.eqz (local.get $y)))
-    )
-    (drop
-      (i32.xor (i32.eqz (local.get $x)) (i32.eqz (local.get $y)))
-    )
-    (drop
-      (i32.and (i32.eqz (local.get $x)) (local.get $y))
-    )
-    (drop
-      (i32.and (local.get $x) (i32.eqz (local.get $y)))
-    )
-    (drop
-      (i32.and (i32.eqz (local.get $x)) (i32.wrap_i64 (i64.const 2)))
-    )
-    (drop
-      (i32.and (i32.wrap_i64 (i64.const 1)) (i32.eqz (local.get $y)))
-    )
-  )
-  (func $subzero1 (param $0 i32) (result i32)
-    (i32.add
-     (i32.sub
-      (i32.const 1)
-      (i32.clz
-       (local.get $0)
-      )
-     )
-     (i32.const 31)
-    )
-  )
-  (func $subzero2 (param $0 i32) (result i32)
-    (i32.add
-     (i32.const 31)
-     (i32.sub
-      (i32.const 1)
-      (i32.clz
-       (local.get $0)
-      )
-     )
-    )
-  )
-  (func $subzero3 (param $0 i32) (param $1 i32) (result i32)
-    (i32.add
-     (i32.sub
-      (i32.const 0)
-      (i32.clz
-       (local.get $0)
-      )
-     )
-     (local.get $1)
-    )
-  )
-  (func $subzero4 (param $0 i32) (param $1 i32) (result i32)
-    (i32.add
-     (local.get $0)
-     (i32.sub
-      (i32.const 0)
-      (i32.clz
-       (local.get $1)
-      )
-     )
-    )
-  )
-  (func $mul-32-power-2 (param $x i32) (result i32)
-    (drop
-      (call $mul-32-power-2
-        (i32.mul
-          (local.get $x)
-          (i32.const 4)
-        )
-      )
-    )
-    (drop
-      (call $mul-32-power-2
-        (i32.mul
-          (local.get $x)
-          (i32.const 5)
-        )
-      )
-    )
-    (drop
-      (call $mul-32-power-2
-        (i32.mul
-          (local.get $x)
-          (i32.const 1)
-        )
-      )
-    )
-    (drop
-      (call $mul-32-power-2
-        (i32.mul
-          (local.get $x)
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (call $mul-32-power-2
-        (i32.mul
-          (call $mul-32-power-2 (i32.const 123)) ;; side effects
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (call $mul-32-power-2
-        (i32.mul
-          (local.get $x)
-          (i32.const 0xffffffff)
-        )
-      )
-    )
-    (drop
-      (call $mul-32-power-2
-        (i32.mul
-          (local.get $x)
-          (i32.const 0x80000000)
-        )
-      )
-    )
-    (unreachable)
-  )
-    (func $mul-64-power-2 (param $x i64) (result i64)
-    (drop
-      (call $mul-64-power-2
-        (i64.mul
-          (local.get $x)
-          (i64.const 4)
-        )
-      )
-    )
-    (drop
-      (call $mul-64-power-2
-        (i64.mul
-          (local.get $x)
-          (i64.const 5)
-        )
-      )
-    )
-    (drop
-      (call $mul-64-power-2
-        (i64.mul
-          (local.get $x)
-          (i64.const 1)
-        )
-      )
-    )
-    (drop
-      (call $mul-64-power-2
-        (i64.mul
-          (local.get $x)
-          (i64.const 0)
-        )
-      )
-    )
-    (drop
-      (call $mul-64-power-2
-        (i64.mul
-          (call $mul-64-power-2 (i64.const 123)) ;; side effects
-          (i64.const 0)
-        )
-      )
-    )
-    (drop
-      (call $mul-64-power-2
-        (i64.mul
-          (local.get $x)
-          (i64.const 0xffffffffffffffff)
-        )
-      )
-    )
-    (drop
-      (call $mul-64-power-2
-        (i64.mul
-          (local.get $x)
-          (i64.const 0x8000000000000000)
-        )
-      )
-    )
-    (unreachable)
-  )
-  (func $div-32-power-2 (param $x i32) (result i32)
-    (drop
-      (call $div-32-power-2
-        (i32.div_u
-          (local.get $x)
-          (i32.const 4)
-        )
-      )
-    )
-    (drop
-      (call $div-32-power-2
-        (i32.div_u
-          (local.get $x)
-          (i32.const 5)
-        )
-      )
-    )
-    (drop
-      (call $div-32-power-2
-        (i32.div_u
-          (local.get $x)
-          (i32.const 1)
-        )
-      )
-    )
-    (drop
-      (call $div-32-power-2
-        (i32.div_u
-          (local.get $x)
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (call $div-32-power-2
-        (i32.div_u
-          (call $div-32-power-2 (i32.const 123)) ;; side effects
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (call $div-32-power-2
-        (i32.div_u
-          (local.get $x)
-          (i32.const 0xffffffff)
-        )
-      )
-    )
-    (drop
-      (call $div-32-power-2
-        (i32.div_u
-          (local.get $x)
-          (i32.const 0x80000000)
-        )
-      )
-    )
-    (unreachable)
-  )
-  (func $urem-32-power-2 (param $x i32) (result i32)
-    (drop
-      (call $urem-32-power-2
-        (i32.rem_u
-          (local.get $x)
-          (i32.const 4)
-        )
-      )
-    )
-    (drop
-      (call $urem-32-power-2
-        (i32.rem_u
-          (local.get $x)
-          (i32.const 5)
-        )
-      )
-    )
-    (drop
-      (call $urem-32-power-2
-        (i32.rem_u
-          (local.get $x)
-          (i32.const 1)
-        )
-      )
-    )
-    (drop
-      (call $urem-32-power-2
-        (i32.rem_u
-          (local.get $x)
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (call $urem-32-power-2
-        (i32.rem_u
-          (local.get $x)
-          (i32.const 0xffffffff)
-        )
-      )
-    )
-    (drop
-      (call $urem-32-power-2
-        (i32.rem_u
-          (local.get $x)
-          (i32.const 0x80000000)
-        )
-      )
-    )
-    ;; (unsigned)x % 1
-    (drop
-      (call $urem-32-power-2
-        (i32.rem_u
-          (local.get $x)
-          (i32.const 1)
-        )
-      )
-    )
-    (unreachable)
-  )
-  (func $srem-by-const (param $x i32) (param $y i64)
-    ;; (signed)x % 1
-    (drop (i32.rem_s
-      (local.get $x)
-      (i32.const 1)
-    ))
-    (drop (i64.rem_s
-      (local.get $y)
-      (i64.const 1)
-    ))
-    ;; (signed)x % 0x80000000 -> x & 0x7FFFFFFF
-    (drop (i32.rem_s
-      (local.get $x)
-      (i32.const 0x80000000)
-    ))
-    ;; (signed)x % 0x8000000000000000 -> x & 0x7FFFFFFFFFFFFFFF
-    (drop (i64.rem_s
-      (local.get $y)
-      (i64.const 0x8000000000000000)
-    ))
-  )
-  (func $srem-by-pot-eq-ne-zero (param $x i32) (param $y i64)
-    ;; eqz((signed)x % 4)
-    (drop (i32.eqz
-      (i32.rem_s
-        (local.get $x)
-        (i32.const 4)
-      )
-    ))
-    (drop (i64.eqz
-      (i64.rem_s
-        (local.get $y)
-        (i64.const 4)
-      )
-    ))
-    ;; eqz((signed)x % -4)
-    (drop (i32.eqz
-      (i32.rem_s
-        (local.get $x)
-        (i32.const -4)
-      )
-    ))
-    (drop (i64.eqz
-      (i64.rem_s
-        (local.get $y)
-        (i64.const -4)
-      )
-    ))
-    ;; (signed)x % 4 == 0
-    (drop (i32.eq
-      (i32.rem_s
-        (local.get $x)
-        (i32.const 4)
-      )
-      (i32.const 0)
-    ))
-    (drop (i64.eq
-      (i64.rem_s
-        (local.get $y)
-        (i64.const 2)
-      )
-      (i64.const 0)
-    ))
-    ;; (signed)x % -4 == 0
-    (drop (i32.eq
-      (i32.rem_s
-        (local.get $x)
-        (i32.const -4)
-      )
-      (i32.const 0)
-    ))
-    (drop (i64.eq
-      (i64.rem_s
-        (local.get $y)
-        (i64.const -4)
-      )
-      (i64.const 0)
-    ))
-    ;; (signed)x % 2 != 0
-    (drop (i32.ne
-      (i32.rem_s
-        (local.get $x)
-        (i32.const 2)
-      )
-      (i32.const 0)
-    ))
-    (drop (i64.ne
-      (i64.rem_s
-        (local.get $y)
-        (i64.const 2)
-      )
-      (i64.const 0)
-    ))
-    ;; (signed)x % -1 == 0  ->  0 == 0
-    (drop (i32.eq
-      (i32.rem_s
-        (local.get $x)
-        (i32.const -1)
-      )
-      (i32.const 0)
-    ))
-    ;; (signed)x % 0x80000000 == 0
-    (drop (i32.eq
-      (i32.rem_s
-        (local.get $x)
-        (i32.const 0x80000000)
-      )
-      (i32.const 0)
-    ))
-    ;; (signed)x % 0x80000000 != 0
-    (drop (i32.ne
-      (i32.rem_s
-        (local.get $x)
-        (i32.const 0x80000000)
-      )
-      (i32.const 0)
-    ))
-    ;; (signed)x % 0x8000000000000000 == 0
-    (drop (i64.eq
-      (i64.rem_s
-        (local.get $y)
-        (i64.const 0x8000000000000000)
-      )
-      (i64.const 0)
-    ))
-    ;; (signed)x % 0x8000000000000000 != 0
-    (drop (i64.ne
-      (i64.rem_s
-        (local.get $y)
-        (i64.const 0x8000000000000000)
-      )
-      (i64.const 0)
-    ))
-    ;;
-    (drop (i32.eq
-      (i32.rem_s
-        (local.get $x)
-        (i32.const 3) ;; skip
-      )
-      (i32.const 0)
-    ))
-    (drop (i64.eq
-      (i64.rem_s
-        (local.get $y)
-        (i64.const 3) ;; skip
-      )
-      (i64.const 0)
-    ))
-  )
-  (func $orZero (param $0 i32) (result i32)
-    (i32.or
-      (local.get $0)
-      (i32.const 0)
-    )
-  )
-  (func $andZero (param $0 i32) (result i32)
-    (drop
-      (i32.and
-        (local.get $0)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.and
-        (call $andZero (i32.const 1234)) ;; side effects
-        (i32.const 0)
-      )
-    )
-    (unreachable)
-  )
-  (func $abstract-additions (param $x32 i32) (param $x64 i64) (param $y32 f32) (param $y64 f64)
-    (drop
-      (i32.or
-        (i32.const 0)
-        (local.get $x32)
-      )
-    )
-    (drop
-      (i32.shl
-        (local.get $x32)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.shr_u
-        (local.get $x32)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (local.get $x32)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i64.or
-        (i64.const 0)
-        (local.get $x64)
-      )
-    )
-    (drop
-      (i64.shl
-        (local.get $x64)
-        (i64.const 0)
-      )
-    )
-    (drop
-      (i64.shr_u
-        (local.get $x64)
-        (i64.const 0)
-      )
-    )
-    (drop
-      (i64.shr_s
-        (local.get $x64)
-        (i64.const 0)
-      )
-    )
-    (drop
-      (i32.mul
-        (local.get $x32)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i64.mul
-        (local.get $x64)
-        (i64.const 0)
-      )
-    )
-    (drop
-      (f32.mul
-        (local.get $y32)
-        (f32.const 0)
-      )
-    )
-    (drop
-      (f64.mul
-        (local.get $y64)
-        (f64.const 0)
-      )
-    )
-    (drop
-      (i32.mul
-        (local.get $x32)
-        (i32.const 1)
-      )
-    )
-    (drop
-      (i64.mul
-        (local.get $x64)
-        (i64.const 1)
-      )
-    )
-    (drop
-      (f32.mul
-        (local.get $y32)
-        (f32.const 1)
-      )
-    )
-    (drop
-      (f64.mul
-        (local.get $y64)
-        (f64.const 1)
-      )
-    )
-    (drop
-      (i32.and
-        (local.get $x32)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i64.and
-        (local.get $x64)
-        (i64.const 0)
-      )
-    )
-    (drop
-      (i32.and
-        (unreachable)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (i64.and
-        (unreachable)
-        (i64.const 0)
-      )
-    )
-    (drop
-      (i32.div_s
-        (local.get $x32)
-        (i32.const 1)
-      )
-    )
-    (drop
-      (i32.div_u
-        (local.get $x32)
-        (i32.const 1)
-      )
-    )
-    (drop
-      (i64.div_s
-        (local.get $x64)
-        (i64.const 1)
-      )
-    )
-    (drop
-      (i64.div_u
-        (local.get $x64)
-        (i64.const 1)
-      )
-    )
-    (drop
-      (f32.div
-        (local.get $y32)
-        (f32.const 1)
-      )
-    )
-    (drop
-      (f64.div
-        (local.get $y64)
-        (f64.const 1)
-      )
-    )
-    (drop
-      (f32.div
-        (local.get $y32)
-        (f32.const 1.2)
-      )
-    )
-    (drop
-      (i32.mul
-        (local.get $x32)
-        (i32.const -1)
-      )
-    )
-    (drop
-      (i64.mul
-        (local.get $x64)
-        (i64.const -1)
-      )
-    )
-    (drop
-      (f32.mul
-        (local.get $y32)
-        (f32.const -1)
-      )
-    )
-    (drop
-      (f64.mul
-        (local.get $y64)
-        (f64.const -1)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.add
-          (local.get $x32)
-          (i32.const 10)
-        )
-        (i32.const 20)
-      )
-    )
-    (drop
-      (i32.le_u
-        (i32.add
-          (local.get $x32)
-          (i32.const 10)
-        )
-        (i32.const 20)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.sub
-          (local.get $x32)
-          (i32.const 10)
-        )
-        (i32.const 20)
-      )
-    )
-    (drop
-      (i64.eq
-        (i64.add
-          (local.get $x64)
-          (i64.const 10)
-        )
-        (i64.const 20)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.const 20)
-        (i32.add
-          (local.get $x32)
-          (i32.const 10)
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.add
-          (local.get $x32)
-          (i32.const 10)
-        )
-        (i32.add
-          (local.get $x32)
-          (i32.const 20)
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.sub
-          (local.get $x32)
-          (i32.const 10)
-        )
-        (i32.const 20)
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.add
-          (local.get $x32)
-          (i32.const 10)
-        )
-        (i32.sub
-          (local.get $x32)
-          (i32.const 20)
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.sub
-          (local.get $x32)
-          (i32.const 10)
-        )
-        (i32.add
-          (local.get $x32)
-          (i32.const 20)
-        )
-      )
-    )
-    (drop
-      (i32.eq
-        (i32.sub
-          (local.get $x32)
-          (i32.const 10)
-        )
-        (i32.sub
-          (local.get $x32)
-          (i32.const 20)
-        )
-      )
-    )
-    (drop
-      (i64.le_s
-        (i64.sub
-          (local.get $x64)
-          (i64.const 288230376151711744)
-        )
-        (i64.const 9223372036854775807)
-      )
-    )
-  )
-  (func $negatives-are-sometimes-better (param $x i32) (param $y i64) (param $z f32)
-    (drop (i32.add (local.get $x) (i32.const 0x40)))
-    (drop (i32.sub (local.get $x) (i32.const 0x40)))
-    (drop (i32.add (local.get $x) (i32.const 0x2000)))
-    (drop (i32.add (local.get $x) (i32.const 0x100000)))
-    (drop (i32.add (local.get $x) (i32.const 0x8000000)))
-
-    (drop (i64.add (local.get $y) (i64.const 0x40)))
-    (drop (i64.sub (local.get $y) (i64.const 0x40)))
-    (drop (i64.add (local.get $y) (i64.const 0x2000)))
-    (drop (i64.add (local.get $y) (i64.const 0x100000)))
-    (drop (i64.add (local.get $y) (i64.const 0x8000000)))
-
-    (drop (i64.add (local.get $y) (i64.const 0x400000000)))
-    (drop (i64.add (local.get $y) (i64.const 0x20000000000)))
-    (drop (i64.add (local.get $y) (i64.const 0x1000000000000)))
-    (drop (i64.add (local.get $y) (i64.const 0x80000000000000)))
-    (drop (i64.add (local.get $y) (i64.const 0x4000000000000000)))
-
-    (drop (f32.add (local.get $z) (f32.const 0x40)))
-  )
-  (func $shift-a-zero (param $x i32) (param $y i64) (param $z f32)
-    (drop
-      (i32.shl
-        (i32.const 0)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.shr_u
-        (i32.const 0)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.shr_s
-        (i32.const 0)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i64.shl
-        (i64.const 0)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i32.shl
-        (i32.const 0)
-        (unreachable)
-      )
-    )
-  )
-  (func $identical-siblings (param $x i32) (param $y i64) (param $z f64) (param $xx i32)
-    (drop
-      (i32.sub
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i64.sub
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (f64.sub
-        (local.get $z)
-        (local.get $z)
-      )
-    )
-    (drop
-      (i32.sub
-        (local.get $x)
-        (local.get $xx)
-      )
-    )
-    (drop
-      (i32.sub
-        (unreachable)
-        (unreachable)
-      )
-    )
-    (drop
-      (i32.add
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    ;; more ops
-    (drop
-      (i32.xor
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.ne
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.lt_s
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.lt_u
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.gt_s
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.gt_u
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.and
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.or
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.eq
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.le_s
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.le_u
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.ge_s
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i32.ge_u
-        (local.get $x)
-        (local.get $x)
-      )
-    )
-    (drop
-      (i64.xor
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.ne
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.lt_s
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.lt_u
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.gt_s
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.gt_u
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.and
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.or
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.eq
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.le_s
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.le_u
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.ge_s
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-    (drop
-      (i64.ge_u
-        (local.get $y)
-        (local.get $y)
-      )
-    )
-  )
-  (func $all_ones (param $x i32) (param $y i64)
-    (drop
-      (i32.and
-        (local.get $x)
-        (i32.const -1)
-      )
-    )
-    (drop
-      (i32.or
-        (local.get $x)
-        (i32.const -1)
-      )
-    )
-    (drop
-      (i32.or
-        (local.tee $x
-          (i32.const 1337)
-        )
-        (i32.const -1)
-      )
-    )
-    (drop
-      (i64.and
-        (local.get $y)
-        (i64.const -1)
-      )
-    )
-    (drop
-      (i64.or
-        (local.get $y)
-        (i64.const -1)
-      )
-    )
-  )
-  (func $xor (param $x i32) (param $y i64)
-    (drop
-      (i32.xor
-        (local.get $x)
-        (i32.const 0)
-      )
-    )
-  )
-  (func $select-on-const (param $x i32) (param $y i64)
-    (drop
-      (select
-        (i32.const 2)
-        (local.get $x)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (select
-        (i32.const 3)
-        (local.get $x)
-        (i32.const 1)
-      )
-    )
-    (drop
-      (select
-        (i32.const 4)
-        (local.tee $x
-          (i32.const 5)
-        )
-        (i32.const 0)
-      )
-    )
-    (drop
-      (select
-        (local.tee $x
-          (i32.const 6)
-        )
-        (i32.const 7)
-        (i32.const 0)
-      )
-    )
-    (drop
-      (select
-        (i32.const 4)
-        (local.tee $x
-          (i32.const 5)
-        )
-        (i32.const 1)
-      )
-    )
-    (drop
-      (select
-        (local.tee $x
-          (i32.const 6)
-        )
-        (i32.const 7)
-        (i32.const 1)
-      )
-    )
-    (drop
-      (select
-        (i32.const 1)
-        (i32.const 0)
-        (local.get $x)
-      )
-    )
-    (drop
-      (select
-        (i32.const 0)
-        (i32.const 1)
-        (local.get $x)
-      )
-    )
-    (drop
-      (select
-        (i32.const 0)
-        (i32.const 1)
-        (i32.lt_s
-          (local.get $x)
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (i32.const 1)
-        (i32.const 0)
-        (i32.lt_s
-          (local.get $x)
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (i32.const 0)
-        (i32.const 1)
-        (i32.ge_s
-          (local.get $x)
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (i32.const 1)
-        (i32.const 0)
-        (i32.gt_s
-          (local.get $x)
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (i32.const 0)
-        (i32.const 1)
-        (i32.gt_s
-          (local.get $x)
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (i32.const 1)
-        (i32.const 0)
-        (i32.ge_s
-          (local.get $x)
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (i64.const 1)
-        (i64.const 0)
-        (local.get $x)
-      )
-    )
-    (drop
-      (select
-        (i64.const 0)
-        (i64.const 1)
-        (local.get $x)
-      )
-    )
-    (drop
-      (select
-        (i64.const 1)
-        (i64.const 0)
-        (i64.eqz
-          (local.get $y)
-        )
-      )
-    )
-    (drop
-      (select
-        (i64.const 0)
-        (i64.const 1)
-        (i64.eqz
-          (local.get $y)
-        )
-      )
-    )
-    (drop
-      (select
-        (i64.const 0)
-        (i64.const 1)
-        (i64.lt_s
-          (local.get $y)
-          (i64.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (i64.const 1)
-        (i64.const 0)
-        (i64.lt_s
-          (local.get $y)
-          (i64.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (i64.const 0)
-        (i64.const 1)
-        (i64.ge_s
-          (local.get $y)
-          (i64.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (i64.const 1)
-        (i64.const 0)
-        (i64.ge_s
-          (local.get $y)
-          (i64.const 0)
-        )
-      )
-    )
-    ;; optimize boolean
-    (drop
-      (select
-        (local.get $x)
-        (i32.const 0)
-        (i32.eqz
-          (i32.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (local.get $x)
-        (i32.const 2)
-        (i32.eqz
-          (i32.const 2)
-        )
-      )
-    )
-    (drop
-      (select
-        (local.get $x)
-        (i32.const 2)
-        (i32.eqz
-          (i32.eqz
-            (local.get $x)
-          )
-        )
-      )
-    )
-    (drop
-      (select
-        (local.get $y)
-        (i64.const 0)
-        (i64.eqz
-          (i64.const 0)
-        )
-      )
-    )
-    (drop
-      (select
-        (local.get $y)
-        (i64.const 2)
-        (i64.eqz
-          (i64.const 2)
-        )
-      )
-    )
-  )
-  (func $optimize-boolean (param $x i32) (param $y i64)
-    ;; bool(-x) -> bool(x)
-    (drop
-      (select
-        (i32.const 1)
-        (i32.const 2)
-        (i32.sub
-          (i32.const 0)
-          (local.get $x)
-        )
-      )
-    )
-    ;; i32(bool(expr)) == 1 -> bool(expr)
-    (drop (i32.eq
-      (i32.and
-        (local.get $x)
-        (i32.const 1)
-      )
-      (i32.const 1)
-    ))
-    ;; i32(bool(expr)) != 1 -> !bool(expr)
-    (drop (i32.ne
-      (i32.and
-        (local.get $x)
-        (i32.const 1)
-      )
-      (i32.const 1)
-    ))
-    ;; i64(bool(expr)) != 0 -> i32(bool(expr))
-    (drop (i64.ne
-      (i64.shr_u
-        (local.get $y)
-        (i64.const 63)
-      )
-      (i64.const 0)
-    ))
-    ;; eqz((i32(bool(expr)) != 0) != 0)
-    (drop (i32.eqz
-      (i32.ne
-        (i32.ne
-          (i32.shr_u
-            (local.get $x)
-            (i32.const 31)
-          )
-          (i32.const 0)
-        )
-        (i32.const 0)
-      )
-    ))
-    ;; i32.eqz(wrap(i64(x)))
-    (drop (i32.eqz
-      (i32.wrap_i64
-        (i64.shr_u
-          (local.get $y)
-          (i64.const 63)
-        )
-      )
-    ))
-    ;; eqz((i64(bool(expr)) != 0) != 0)
-    (drop (i32.eqz
-      (i32.ne
-        (i64.ne
-          (i64.shr_u
-            (local.get $y)
-            (i64.const 63)
-          )
-          (i64.const 0)
-        )
-        (i32.const 0)
-      )
-    ))
-    ;; eqz((i64(bool(expr)) != 0) != 0)
-    (drop (i32.eqz
-      (i32.ne
-        (i64.ne
-          (local.get $y)
-          (i64.const 0)
-        )
-        (i32.const 0)
-      )
-    ))
-    ;; i32.eqz(wrap(i64(x))) -> skip
-    (drop (i32.eqz
-      (i32.wrap_i64
-        (local.get $y)
-      )
-    ))
-    ;; i64(bool(expr)) == 1 -> i32(bool(expr))
-    (drop (i64.eq
-      (i64.and
-        (local.get $y)
-        (i64.const 1)
-      )
-      (i64.const 1)
-    ))
-    ;; i64(bool(expr)) != 1 -> !i64(bool(expr))
-    (drop (i64.ne
-      (i64.and
-        (local.get $y)
-        (i64.const 1)
-      )
-      (i64.const 1)
-    ))
-    ;; i32(bool(expr)) & 1 -> bool(expr)
-    (drop (i32.and
-      (i32.and
-        (local.get $x)
-        (i32.const 1)
-      )
-      (i32.const 1)
-    ))
-    ;; i32(bool(expr)) | 1 -> 1
-    (drop (i32.or
-      (i32.and
-        (local.get $x)
-        (i32.const 1)
-      )
-      (i32.const 1)
-    ))
-    ;; i64(bool(expr)) & 1 -> i64(bool(expr))
-    (drop (i64.and
-      (i64.and
-        (local.get $y)
-        (i64.const 1)
-      )
-      (i64.const 1)
-    ))
-    ;; i64(bool(expr)) | 1 -> 1
-    (drop (i64.or
-      (i64.and
-        (local.get $y)
-        (i64.const 1)
-      )
-      (i64.const 1)
-    ))
-  )
-  (func $optimize-bitwise-oprations (param $x i32) (param $y i32) (param $z i64) (param $w i64)
-    ;; ~(1 << x)  ->  rotl(-2, x)
-    (drop (i32.xor
-      (i32.shl
-        (i32.const 1)
-        (local.get $x)
-      )
-      (i32.const -1)
-    ))
-    (drop (i64.xor
-      (i64.shl
-        (i64.const 1)
-        (local.get $z)
-      )
-      (i64.const -1)
-    ))
-  )
-  (func $getFallthrough ;; unit tests for Properties::getFallthrough
-    (local $x0 i32)
-    (local $x1 i32)
-    (local $x2 i32)
-    (local $x3 i32)
-    (local $x4 i32)
-    (local $x5 i32)
-    (local $x6 i32)
-    (local $x7 i32)
-    ;; the trivial case
-    (local.set $x0 (i32.const 1))
-    (drop (i32.and (local.get $x0) (i32.const 7)))
-    ;; tees
-    (local.set $x1 (local.tee $x2 (i32.const 1)))
-    (drop (i32.and (local.get $x1) (i32.const 7)))
-    ;; loop
-    (local.set $x3 (loop (result i32) (i32.const 1)))
-    (drop (i32.and (local.get $x3) (i32.const 7)))
-    ;; if - two sides, can't
-    (local.set $x4 (if (result i32) (i32.const 1) (i32.const 2) (i32.const 3)))
-    (drop (i32.and (local.get $x4) (i32.const 7)))
-    ;; if - one side, can
-    (local.set $x5 (if (result i32) (i32.const 1) (unreachable) (i32.const 3)))
-    (drop (i32.and (local.get $x5) (i32.const 7)))
-    ;; if - one side, can
-    (local.set $x6 (if (result i32) (i32.const 1) (i32.const 3) (unreachable)))
-    (drop (i32.and (local.get $x6) (i32.const 7)))
-    ;; br_if with value
-    (drop
-      (block $out (result i32)
-        (local.set $x7 (br_if $out (i32.const 1) (i32.const 1)))
-        (drop (i32.and (local.get $x7) (i32.const 7)))
-        (unreachable)
-      )
-    )
-  )
-  (func $tee-with-unreachable-value (result f64)
-   (local $var$0 i32)
-   (block $label$1 (result f64)
-    (local.tee $var$0
-     (br_if $label$1 ;; the f64 does not actually flow through this, it's unreachable (and the type is wrong - but unchecked)
-      (f64.const 1)
-      (unreachable)
-     )
-    )
-   )
-  )
-  (func $add-sub-zero-reorder-1 (param $temp i32) (result i32)
-   (i32.add
-    (i32.add
-     (i32.sub
-      (i32.const 0) ;; this zero looks like we could remove it by subtracting the get of $temp from the parent, but that would reorder it *after* the tee :(
-      (local.get $temp)
-     )
-     (local.tee $temp ;; cannot move this tee before the get
-      (i32.const 1)
-     )
-    )
-    (i32.const 2)
-   )
-  )
-  (func $add-sub-zero-reorder-2 (param $temp i32) (result i32)
-   (i32.add
-    (i32.add
-     (local.tee $temp ;; in this order, the tee already comes first, so all is good for the optimization
-      (i32.const 1)
-     )
-     (i32.sub
-      (i32.const 0)
-      (local.get $temp)
-     )
-    )
-    (i32.const 2)
-   )
-  )
-  (func $const-float-zero (param $fx f32) (param $fy f64)
-    ;; x - 0.0   ==>   x
-    (drop (f32.sub
-      (local.get $fx)
-      (f32.const 0)
-    ))
-    (drop (f64.sub
-      (local.get $fy)
-      (f64.const 0)
-    ))
-    ;; x + (-0.0)   ==>   x
-    (drop (f32.add
-      (local.get $fx)
-      (f32.const -0)
-    ))
-    (drop (f64.add
-      (local.get $fy)
-      (f64.const -0)
-    ))
-    ;; x - (-0.0)   ==>   x + 0.0
-    (drop (f32.sub
-      (local.get $fx)
-      (f32.const -0) ;; skip
-    ))
-    (drop (f64.sub
-      (local.get $fy)
-      (f64.const -0) ;; skip
-    ))
-    ;; 0.0 - x   ==>   0.0 - x
-    (drop (f32.sub
-      (f32.const 0)
-      (local.get $fx) ;; skip
-    ))
-    (drop (f64.sub
-      (f64.const 0)
-      (local.get $fy) ;; skip
-    ))
-    ;; x + 0.0   ==>   x + 0.0
-    (drop (f32.add
-      (local.get $fx) ;; skip
-      (f32.const 0)
-    ))
-    (drop (f64.add
-      (local.get $fy) ;; skip
-      (f64.const 0)
-    ))
-    (drop (f32.sub
-      (f32.const -nan:0x34546d) ;; skip
-      (f32.const 0)
-    ))
-  )
-  (func $rhs-is-neg-one (param $x i32) (param $y i64) (param $fx f32) (param $fy f64)
-    (drop (i32.sub
-      (local.get $x)
-      (i32.const -1)
-    ))
-    (drop (i64.sub
-      (local.get $y)
-      (i64.const -1)
-    ))
-    (drop (i32.gt_u
-      (local.get $x)
-      (i32.const -1)
-    ))
-    (drop (i64.gt_u
-      (local.get $y)
-      (i64.const -1)
-    ))
-    (drop (i32.gt_s
-      (local.get $x)
-      (i32.const -1)
-    ))
-    (drop (i64.gt_s
-      (local.get $y)
-      (i64.const -1)
-    ))
-    (drop (i64.extend_i32_s
-      (i64.gt_u
-        (i64.const 0)
-        (i64.const -1)
-      )
-    ))
-    ;; (unsigned)x <= -1   ==>   1
-    (drop (i32.le_u
-      (local.get $x)
-      (i32.const -1)
-    ))
-    (drop (i64.le_u
-      (local.get $y)
-      (i64.const -1)
-    ))
-    (drop (i32.le_s
-      (local.get $x)
-      (i32.const -1)
-    ))
-    (drop (i64.le_s
-      (local.get $y)
-      (i64.const -1)
-    ))
-    ;; x * -1
-    (drop (i32.mul
-      (local.get $x)
-      (i32.const -1)
-    ))
-    (drop (i64.mul
-      (local.get $y)
-      (i64.const -1)
-    ))
-    (drop (f32.mul    ;; skip
-      (local.get $fx)
-      (f32.const -1)
-    ))
-    (drop (f64.mul    ;; skip
-      (local.get $fy)
-      (f64.const -1)
-    ))
-    ;; (unsigned)x / -1
-    (drop (i32.div_u
-      (local.get $x)
-      (i32.const -1)
-    ))
-    (drop (i64.div_u
-      (local.get $y)
-      (i64.const -1)
-    ))
-  )
-  (func $rhs-is-neg-const (param $x i32) (param $y i64)
-    ;; u32(x) / -2  =>  x >= -2
-    (drop (i32.div_u
-      (local.get $x)
-      (i32.const -2)
-    ))
-    ;; u32(x) / -1  =>  x == -1
-    (drop (i32.div_u
-      (local.get $x)
-      (i32.const -1)
-    ))
-    ;; u32(x) / (i32.min + 1)
-    (drop (i32.div_u
-      (local.get $x)
-      (i32.const -2147483647)
-    ))
-    ;; u32(x) / i32.min  =>  x >>> 31
-    (drop (i32.div_u
-      (local.get $x)
-      (i32.const -2147483648)
-    ))
-    ;; u64(x) / -1  =>  u64(x == -1)
-    (drop (i64.div_u
-      (local.get $y)
-      (i64.const -1)
-    ))
-    ;; u64(x) / i64.min  =>  x >>> 63
-    (drop (i64.div_u
-      (local.get $y)
-      (i64.const -9223372036854775808)
-    ))
-  )
-  (func $pre-combine-or (param $x i32) (param $y i32)
-    (drop (i32.or
-      (i32.gt_s
-        (local.get $x)
-        (local.get $y)
-      )
-      (i32.eq
-        (local.get $y) ;; ordering should not stop us
-        (local.get $x)
-      )
-    ))
-    (drop (i32.or
-      (i32.eq ;; ordering should not stop us
-        (local.get $y)
-        (local.get $x)
-      )
-      (i32.gt_s
-        (local.get $x)
-        (local.get $y)
-      )
-    ))
-    (drop (i32.or
-      (i32.gt_s
-        (local.get $x)
-        (local.get $y)
-      )
-      (i32.eq
-        (local.get $x)
-        (i32.const 1) ;; not equal
-      )
-    ))
-    (drop (i32.or
-      (i32.gt_s
-        (local.get $x)
-        (i32.const 1) ;; not equal
-      )
-      (i32.eq
-        (local.get $x)
-        (local.get $y)
-      )
-    ))
-    (drop (i32.or
-      (i32.gt_s
-        (call $ne0) ;; side effects
-        (local.get $y)
-      )
-      (i32.eq
-        (call $ne0)
-        (local.get $y)
-      )
-    ))
-    (drop (i32.or
-      (i32.gt_s
-        (local.get $y)
-        (call $ne0) ;; side effects
-      )
-      (i32.eq
-        (local.get $y)
-        (call $ne0)
-      )
-    ))
-  )
-  (func $combine-or (param $x i32) (param $y i32)
-    (drop (i32.or
-      (i32.gt_s
-        (local.get $x)
-        (local.get $y)
-      )
-      (i32.eq
-        (local.get $x)
-        (local.get $y)
-      )
-    ))
-    ;; TODO: more stuff here
-  )
-  (func $select-into-arms (param $x i32) (param $y i32)
-    (if
-      (select
-        (i32.eqz (i32.eqz (local.get $x)))
-        (i32.eqz (i32.eqz (local.get $y)))
-        (local.get $y)
-      )
-      (unreachable)
-    )
-  )
-  ;; These functions test if an `if` with subtyped arms is correctly folded
-  ;; 1. if its `ifTrue` and `ifFalse` arms are identical (can fold)
-  (func $if-arms-subtype-fold (result anyref)
-    (if (result anyref)
-      (i32.const 0)
-      (ref.null extern)
-      (ref.null extern)
-    )
-  )
-  ;; 2. if its `ifTrue` and `ifFalse` arms are not identical (cannot fold)
-  (func $if-arms-subtype-nofold (result anyref)
-    (if (result anyref)
-      (i32.const 0)
-      (ref.null extern)
-      (ref.null func)
-    )
-  )
-  (func $optimize-boolean-context (param $x i32) (param $y i32)
-    ;; 0 - x   ==>   x
-    (if
-      (i32.sub
-        (i32.const 0)
-        (local.get $x)
-      )
-      (unreachable)
-    )
-    (drop (select
-      (local.get $x)
-      (local.get $y)
-      (i32.sub
-        (i32.const 0)
-        (local.get $x)
-      )
-    ))
-  )
-  (func $unsigned-context (param $x i32) (param $y i64)
-    (drop (i32.div_s
-      (i32.and
-        (local.get $x)
-        (i32.const 0x7fffffff)
-      )
-      (i32.const 3)
-    ))
-    (drop (i32.div_s
-      (i32.and
-        (local.get $x)
-        (i32.const 0x7fffffff)
-      )
-      (i32.const -3) ;; skip
-    ))
-    (drop (i32.div_s
-      (i32.and
-        (local.get $x)
-        (i32.const 0x7fffffff)
-      )
-      (i32.const 0x80000000) ;; skip
-    ))
-    (drop (i64.div_s
-      (i64.and
-        (local.get $y)
-        (i64.const 0x7fffffffffffffff)
-      )
-      (i64.const 2)
-    ))
-     (drop (i64.div_s
-      (i64.and
-        (local.get $y)
-        (i64.const 0x7fffffffffffffff)
-      )
-      (i64.const -1) ;; skip
-    ))
-    (drop (i32.rem_s
-      (i32.and
-        (local.get $x)
-        (i32.const 0x7fffffff)
-      )
-      (i32.const 3)
-    ))
-    (drop (i32.shr_s
-      (i32.and
-        (local.get $x)
-        (i32.const 0x7fffffff)
-      )
-      (i32.const 7)
-    ))
-    (drop (i32.ge_s
-      (i32.and
-        (local.get $x)
-        (i32.const 0x7fffffff)
-      )
-      (i32.const 7)
-    ))
-    (drop (i32.ge_s
-      (i32.and
-        (local.get $x)
-        (i32.const 0x7fffffff)
-      )
-      (i32.const -7) ;; skip
-    ))
-  )
-  (func $duplicate-elimination (param $x i32) (param $y i32) (param $z i32) (param $w f64)
-    ;; unary
-    (drop (f64.abs (f64.abs (local.get $w))))
-    (drop (f64.ceil (f64.ceil (local.get $w))))
-    (drop (f64.floor (f64.floor (local.get $w))))
-    (drop (f64.trunc (f64.trunc (local.get $w))))
-    (drop (f64.nearest (f64.nearest (local.get $w))))
-
-    (drop (f64.nearest (f64.trunc (local.get $w)))) ;; skip
-    (drop (f64.trunc (f64.nearest (local.get $w)))) ;; skip
-
-    (drop (f64.neg (f64.neg (local.get $w))))
-    (drop (f64.neg (f64.neg (f64.neg (local.get $w)))))
-    (drop (f64.neg (f64.neg (f64.neg (f64.neg (local.get $w))))))
-
-    (drop (i32.eqz (i32.eqz (local.get $x)))) ;; skip
-    (drop (i32.eqz (i32.eqz (i32.eqz (local.get $x)))))
-    (drop (i32.eqz (i32.eqz (i64.eqz (i64.const 1)))))
-    (drop (i32.eqz (i32.eqz (i32.ne (local.get $x) (i32.const 2)))))
-
-    (drop (i32.extend8_s (i32.extend8_s (local.get $x))))
-    (drop (i32.extend16_s (i32.extend16_s (local.get $x))))
-    (drop (i32.eqz
-      (i32.eqz
-        (i32.and
-          (local.get $x)
-          (i32.const 1)
-        )
-      )
-    ))
-
-    ;; binary
-    ;; ((signed)x % y) % y
-    (drop (i32.rem_s
-      (i32.rem_s
-        (local.get $x)
-        (local.get $y)
-      )
-      (local.get $y)
-    ))
-    ;; ((unsigned)x % y) % y
-    (drop (i32.rem_u
-      (i32.rem_u
-        (local.get $x)
-        (local.get $y)
-      )
-      (local.get $y)
-    ))
-    ;; 0 - (0 - y)
-    (drop (i32.sub
-      (i32.const 0)
-      (i32.sub
-        (i32.const 0)
-        (local.get $y)
-      )
-    ))
-    ;; x - (x - y)
-    (drop (i32.sub
-      (local.get $x)
-      (i32.sub
-        (local.get $x)
-        (local.get $y)
-      )
-    ))
-    ;; y - (x - y)   -   skip
-    (drop (i32.sub
-      (local.get $y)
-      (i32.sub
-        (local.get $x)
-        (local.get $y)
-      )
-    ))
-    ;; x ^ (x ^ y)
-    (drop (i32.xor
-      (local.get $x)
-      (i32.xor
-        (local.get $x)
-        (local.get $y)
-      )
-    ))
-    ;; x ^ (y ^ x)
-    (drop (i32.xor
-      (local.get $x)
-      (i32.xor
-        (local.get $y)
-        (local.get $x)
-      )
-    ))
-    ;; (x ^ y) ^ x
-    (drop (i32.xor
-      (i32.xor
-        (local.get $x)
-        (local.get $y)
-      )
-      (local.get $x)
-    ))
-    ;; (y ^ x) ^ x
-    (drop (i32.xor
-      (i32.xor
-        (local.get $y)
-        (local.get $x)
-      )
-      (local.get $x)
-    ))
-    ;; x ^ (x ^ x)
-    (drop (i32.xor
-      (local.get $x)
-      (i32.xor
-        (local.get $x)
-        (local.get $x)
-      )
-    ))
-    ;; x & (x & y)
-    (drop (i32.and
-      (local.get $x)
-      (i32.and
-        (local.get $x)
-        (local.get $y)
-      )
-    ))
-    ;; x & (y & x)
-    (drop (i32.and
-      (local.get $x)
-      (i32.and
-        (local.get $y)
-        (local.get $x)
-      )
-    ))
-    ;; (x & y) & x
-    (drop (i32.and
-      (i32.and
-        (local.get $x)
-        (local.get $y)
-      )
-      (local.get $x)
-    ))
-    ;; (y & x) & x
-    (drop (i32.and
-      (i32.and
-        (local.get $y)
-        (local.get $x)
-      )
-      (local.get $x)
-    ))
-    ;; x | (x | y)
-    (drop (i32.or
-      (local.get $x)
-      (i32.or
-        (local.get $x)
-        (local.get $y)
-      )
-    ))
-    ;; x | (y | x)
-    (drop (i32.or
-      (local.get $x)
-      (i32.or
-        (local.get $y)
-        (local.get $x)
-      )
-    ))
-    ;; (x | y) | x
-    (drop (i32.or
-      (i32.or
-        (local.get $x)
-        (local.get $y)
-      )
-      (local.get $x)
-    ))
-    ;; (y | x) | x
-    (drop (i32.or
-      (i32.or
-        (local.get $y)
-        (local.get $x)
-      )
-      (local.get $x)
-    ))
-    ;; (y | x) | z   -   skip
-    (drop (i32.or
-      (i32.or
-        (local.get $y)
-        (local.get $x)
-      )
-      (local.get $z)
-    ))
-    ;; (z | x) | y   -   skip
-    (drop (i32.or
-      (i32.or
-        (local.get $z)
-        (local.get $x)
-      )
-      (local.get $y)
-    ))
-    ;; (SE() | x) | x
-    (drop (i32.or
-      (i32.or
-        (call $ne0) ;; side effect
-        (local.get $x)
-      )
-      (local.get $x)
-    ))
-    ;; (x | SE()) | SE()   -   skip
-    (drop (i32.or
-      (i32.or
-        (local.get $x)
-        (call $ne0) ;; side effect
-      )
-      (call $ne0) ;; side effect
-    ))
-    ;; x | (SE() | x)
-    (drop (i32.or
-      (local.get $x)
-      (i32.or
-        (local.get $x)
-        (call $ne0) ;; side effect
-      )
-    ))
-    ;; SE() | (x | SE())   -   skip
-    (drop (i32.or
-      (call $ne0) ;; side effect
-      (i32.or
-        (call $ne0) ;; side effect
-        (local.get $x)
-      )
-    ))
-    ;; (y % x) % y   -   skip
-    (drop (i32.rem_s
-      (i32.rem_s
-        (local.get $y)
-        (local.get $x)
-      )
-      (local.get $y)
-    ))
-    ;; y % (x % y)   -   skip
-    (drop (i32.rem_u
-      (local.get $y)
-      (i32.rem_u
-        (local.get $x)
-        (local.get $y)
-      )
-     ))
-    ;; x | (y | x)   where x and y cannot be reordered  -  skip
-    (drop
-      (i32.or
-        (local.get $x)
-        (i32.or
-          (local.tee $x
-            (i32.const 1)
-          )
-          (local.get $x)
-        )
-      )
-    )
-    (drop
-      (i32.or
-        (i32.or
-          (local.get $x)
-          (local.tee $x
-            (i32.const 1)
-          )
-        )
-        (local.get $x)
-      )
-    )
-    ;; x ^ (y ^ x)   where x and y cannot be reordered  -  skip
-    (drop
-      (i32.xor
-        (local.get $x)
-        (i32.xor
-          (local.tee $x
-            (i32.const 1)
-          )
-          (local.get $x)
-        )
-      )
-    )
-    (drop
-      (i32.xor
-        (i32.xor
-          (local.get $x)
-          (local.tee $x
-            (i32.const 1)
-          )
-        )
-        (local.get $x)
-      )
-    )
-  )
-  (func $optimize-shifts (param $x i32) (param $y i32) (param $z i64) (param $w i64)
-    ;; i32
-    (drop (i32.shl
-      (local.get $x)
-      (i32.const 32)
-    ))
-    (drop (i32.shr_s
-      (local.get $x)
-      (i32.const 32)
-    ))
-    (drop (i32.shr_u
-      (local.get $x)
-      (i32.const 64)
-    ))
-    (drop (i32.rotl
-      (local.get $x)
-      (i32.const 64)
-    ))
-    (drop (i32.rotr
-      (local.get $x)
-      (i32.const 64)
-    ))
-    ;; i64
-    (drop (i64.shl
-      (local.get $z)
-      (i64.const 64)
-    ))
-    (drop (i64.shr_s
-      (local.get $z)
-      (i64.const 64)
-    ))
-    (drop (i64.shr_u
-      (local.get $z)
-      (i64.const 128)
-    ))
-    (drop (i64.rotl
-      (local.get $z)
-      (i64.const 128)
-    ))
-    (drop (i64.rotr
-      (local.get $z)
-      (i64.const 128)
-    ))
-
-    ;; i32
-    (drop (i32.shl
-      (local.get $x)
-      (i32.and
-        (local.get $y)
-        (i32.const 31)
-      )
-    ))
-    (drop (i32.shl
-      (local.get $x)
-      (i32.and
-        (local.get $y)
-        (i32.const 63)
-      )
-    ))
-    (drop (i32.shr_s
-      (local.get $x)
-      (i32.and
-        (local.get $y)
-        (i32.const 31)
-      )
-    ))
-    (drop (i32.shr_u
-      (local.get $x)
-      (i32.and
-        (local.get $y)
-        (i32.const 31)
-      )
-    ))
-    ;; i64
-    (drop (i64.shl
-      (local.get $z)
-      (i64.and
-        (local.get $w)
-        (i64.const 63)
-      )
-    ))
-    (drop (i64.shl
-      (local.get $z)
-      (i64.and
-        (local.get $w)
-        (i64.const 127)
-      )
-    ))
-    (drop (i64.shr_s
-      (local.get $z)
-      (i64.and
-        (local.get $w)
-        (i64.const 63)
-      )
-    ))
-    (drop (i64.shr_u
-      (local.get $z)
-      (i64.and
-        (local.get $w)
-        (i64.const 63)
-      )
-    ))
-
-    ;; skip
-    (drop (i32.shl
-      (local.get $x)
-      (i32.and
-        (local.get $y)
-        (i32.const 32)
-      )
-    ))
-    ;; skip
-    (drop (i64.shr_u
-      (local.get $z)
-      (i64.and
-        (local.get $w)
-        (i64.const 31)
-      )
-    ))
-  )
-  (func $optimize-bulk-memory-copy (param $dst i32) (param $src i32) (param $sz i32)
-    (memory.copy  ;; skip
-      (local.get $dst)
-      (local.get $dst)
-      (local.get $sz)
-    )
-
-    (memory.copy  ;; skip
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 0)
-    )
-
-    (memory.copy
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 1)
-    )
-
-    (memory.copy
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 2)
-    )
-
-    (memory.copy
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 3)
-    )
-
-    (memory.copy
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 4)
-    )
-
-    (memory.copy
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 5)
-    )
-
-    (memory.copy
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 6)
-    )
-
-    (memory.copy
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 7)
-    )
-
-    (memory.copy
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 8)
-    )
-
-    (memory.copy
-      (local.get $dst)
-      (local.get $src)
-      (i32.const 16)
-    )
-
-    (memory.copy  ;; skip
-      (local.get $dst)
-      (local.get $src)
-      (local.get $sz)
-    )
-
-    (memory.copy  ;; skip
-      (i32.const 0)
-      (i32.const 0)
-      (i32.load
-        (i32.const 3) ;; side effect
-      )
-    )
-  )
-)
-(module
-  (import "env" "memory" (memory $0 (shared 256 256)))
-  (func $x
-   (drop
-    (i32.shr_s
-     (i32.shl
-      (i32.atomic.load8_u ;; can't be signed
-       (i32.const 100)
-      )
-      (i32.const 24)
-     )
-     (i32.const 24)
-    )
-   )
+    (drop
+      (i32.and
+        (i32.and
+          (local.get $i1)
+          (i32.const 5)
+        )
+        (i32.const 3)
+      )
+    )
+    (drop
+      (i32.or
+        (i32.or
+          (local.get $i1)
+          (i32.const 1)
+        )
+        (i32.const 2)
+      )
+    )
+    (drop
+      (i32.xor
+        (i32.xor
+          (local.get $i1)
+          (i32.const -2)
+        )
+        (i32.const -5)
+      )
+    )
+    (drop
+      (i32.mul
+        (i32.mul
+          (local.get $i1)
+          (i32.const -2)
+        )
+        (i32.const 5)
+      )
+    )
+    ;; overflow also valid
+    (drop
+      (i32.mul
+        (i32.mul
+          (local.get $i1)
+          (i32.const 0xfffff)
+        )
+        (i32.const 0x8000001)
+      )
+    )
+    (if
+      (i32.eqz
+        (local.get $i1)
+      )
+      (drop
+        (i32.const 10)
+      )
+    )
+    (if
+      (i32.eqz
+        (local.get $i1)
+      )
+      (drop
+        (i32.const 11)
+      )
+      (drop
+        (i32.const 12)
+      )
+    )
+    (if
+      (i64.eqz
+        (local.get $i2)
+      )
+      (drop
+        (i32.const 11)
+      )
+      (drop
+        (i32.const 12)
+      )
+    )
+    (drop
+      (i32.eqz
+        (i32.gt_s
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (i32.ge_s
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (i32.lt_s
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (i32.le_s
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (i32.gt_u
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (i32.ge_u
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (i32.lt_u
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (i32.le_u
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f32.gt
+          (f32.const 1)
+          (f32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f32.ge
+          (f32.const 1)
+          (f32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f32.lt
+          (f32.const 1)
+          (f32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f32.le
+          (f32.const 1)
+          (f32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f64.gt
+          (f64.const 1)
+          (f64.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f64.ge
+          (f64.const 1)
+          (f64.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f64.lt
+          (f64.const 1)
+          (f64.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f64.le
+          (f64.const 1)
+          (f64.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f32.eq
+          (f32.const 1)
+          (f32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f32.ne
+          (f32.const 1)
+          (f32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f64.eq
+          (f64.const 1)
+          (f64.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.eqz
+        (f64.ne
+          (f64.const 1)
+          (f64.const 2)
+        )
+      )
+    )
+    ;; we handle only 0 in the right position, as we assume a const is there, and don't care about if
+    ;; both are consts here (precompute does that, so no need)
+    (drop
+      (i32.eq
+        (i32.const 100)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.const 0)
+        (i32.const 100)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.const 0)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i64.eq
+        (i64.const 100)
+        (i64.const 0)
+      )
+    )
+    (drop
+      (i64.eq
+        (i64.const 0)
+        (i64.const 100)
+      )
+    )
+    (drop
+      (i64.eq
+        (i64.const 0)
+        (i64.const 0)
+      )
+    )
+    (if
+      (i32.eqz
+        (i32.eqz
+          (i32.const 123)
+        )
+      )
+      (nop)
+    )
+    (drop
+      (select
+        (i32.const 101)
+        (i32.const 102)
+        (i32.eqz
+          (local.get $i1)
+        )
+      )
+    )
+    (drop
+      (select
+        (local.tee $i1
+          (i32.const 103)
+        ) ;; these conflict
+        (local.tee $i1
+          (i32.const 104)
+        )
+        (i32.eqz
+          (local.get $i1)
+        )
+      )
+    )
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 1)
+        (i32.eqz
+          (i32.eqz
+            (i32.const 2)
+          )
+        )
+      )
+    )
+  )
+  (func $load-store
+    (drop (i32.and (i32.load8_s (i32.const 0)) (i32.const 255)))
+    (drop (i32.and (i32.load8_u (i32.const 1)) (i32.const 255)))
+    (drop (i32.and (i32.load8_s (i32.const 2)) (i32.const 254)))
+    (drop (i32.and (i32.load8_u (i32.const 3)) (i32.const 1)))
+    (drop (i32.and (i32.load16_s (i32.const 4)) (i32.const 65535)))
+    (drop (i32.and (i32.load16_u (i32.const 5)) (i32.const 65535)))
+    (drop (i32.and (i32.load16_s (i32.const 6)) (i32.const 65534)))
+    (drop (i32.and (i32.load16_u (i32.const 7)) (i32.const 1)))
+    ;;
+    (i32.store8 (i32.const 8) (i32.and (i32.const -1) (i32.const 255)))
+    (i32.store8 (i32.const 9) (i32.and (i32.const -2) (i32.const 254)))
+    (i32.store16 (i32.const 10) (i32.and (i32.const -3) (i32.const 65535)))
+    (i32.store16 (i32.const 11) (i32.and (i32.const -4) (i32.const 65534)))
+    ;;
+    (i32.store8 (i32.const 11) (i32.wrap_i64 (i64.const 1)))
+    (i32.store16 (i32.const 11) (i32.wrap_i64 (i64.const 2)))
+    (i32.store (i32.const 11) (i32.wrap_i64 (i64.const 3)))
+    ;;
+    (i32.store8 (i32.const 7) (i32.const -1))           ;; 255
+    (i32.store8 (i32.const 8) (i32.const 255))
+    (i32.store8 (i32.const 9) (i32.const 256))          ;; 0
+    (i32.store16 (i32.const 10) (i32.const 65535))
+    (i32.store16 (i32.const 11) (i32.const 65536))      ;; 0
+    (i32.store16 (i32.const 13) (i32.const -1))         ;; 65535
+    (i32.store (i32.const 14) (i32.const 65536))
+    ;;
+    (i64.store8 (i32.const 8) (i64.const 255))
+    (i64.store8 (i32.const 9) (i64.const 256))          ;; 0
+    (i64.store16 (i32.const 10) (i64.const 65535))
+    (i64.store16 (i32.const 11) (i64.const 65536))      ;; 0
+    (i64.store32 (i32.const 12) (i64.const 4294967295))
+    (i64.store32 (i32.const 13) (i64.const 4294967296)) ;; 0
+    (i64.store (i32.const 14) (i64.const 4294967296))
+  )
+  (func $and-neg1
+    (drop (i32.and (i32.const 100) (i32.const -1)))
+    (drop (i32.and (i32.const 100) (i32.const  1)))
+  )
+  (func $and-pos1
+    (drop (i32.and (i32.eqz (i32.const 1000)) (i32.const 1)))
+    (drop (i32.and (i32.const 1) (i32.eqz (i32.const 1000))))
+    (drop (i32.and (i32.const 100) (i32.const 1)))
+    (drop (i32.and (i32.lt_s (i32.const 2000) (i32.const 3000)) (i32.const 1)))
+  )
+  (func $canonicalize (param $x i32) (param $y i32) (param $fx f64) (param $fy f64)
+    (drop (i32.and (unreachable) (i32.const 1))) ;; ok to reorder
+    (drop (i32.and (i32.const 1) (unreachable)))
+    (drop (i32.div_s (unreachable) (i32.const 1))) ;; not ok
+    (drop (i32.div_s (i32.const 1) (unreachable)))
+    ;; the various orderings
+    (drop (i32.and (i32.const 1) (i32.const 2)))
+    (drop (i32.and (local.get $x) (i32.const 3)))
+    (drop (i32.and (i32.const 4) (local.get $x)))
+    (drop (i32.and (local.get $x) (local.get $y)))
+    (drop (i32.and (local.get $y) (local.get $x)))
+    (drop (i32.and (local.get $y) (local.tee $x (i32.const -4))))
+    (drop (i32.and
+      (block (result i32)
+        (i32.const -5)
+      )
+      (local.get $x)
+    ))
+    (drop (i32.and
+      (local.get $x)
+      (block (result i32)
+        (i32.const -6)
+      )
+    ))
+    (drop (i32.and
+      (block (result i32)
+        (i32.const 5)
+      )
+      (loop (result i32)
+        (i32.const 6)
+      )
+    ))
+    (drop (i32.and
+      (loop (result i32)
+        (i32.const 7)
+      )
+      (block (result i32)
+        (i32.const 8)
+      )
+    ))
+    (drop (i32.and
+      (loop (result i32)
+        (call $and-pos1)
+        (i32.const 9)
+      )
+      (block (result i32)
+        (i32.const 10)
+      )
+    ))
+    (drop (i32.and
+      (loop (result i32)
+        (i32.const 11)
+      )
+      (block (result i32)
+        (call $and-pos1)
+        (i32.const 12)
+      )
+    ))
+    (drop (i32.and
+      (loop (result i32)
+        (call $and-pos1)
+        (i32.const 13)
+      )
+      (block (result i32)
+        (call $and-pos1)
+        (i32.const 14)
+      )
+    ))
+    (drop (i32.and
+      (block (result i32)
+        (call $and-pos1)
+        (i32.const 14)
+      )
+      (loop (result i32)
+        (call $and-pos1)
+        (i32.const 13)
+      )
+    ))
+    (drop (i32.and
+      (block (result i32)
+        (i32.const 15)
+      )
+      (local.get $x)
+    ))
+    (drop (i32.and
+      (local.get $x)
+      (block (result i32)
+        (i32.const 15)
+      )
+    ))
+    (drop (i32.and
+      (i32.gt_s
+        (i32.const 16)
+        (i32.const 17)
+      )
+      (i32.gt_u
+        (i32.const 18)
+        (i32.const 19)
+      )
+    ))
+    (drop (i32.and
+      (i32.gt_u
+        (i32.const 20)
+        (i32.const 21)
+      )
+      (i32.gt_s
+        (i32.const 22)
+        (i32.const 23)
+      )
+    ))
+    (drop (i32.gt_s
+      (i32.const 1)
+      (local.get $x)
+    ))
+    (drop (i32.gt_u
+      (i32.const 0)
+      (local.get $x)
+    ))
+    (drop (i32.ne
+      (i32.const -1)
+      (local.get $x)
+    ))
+    (drop (f64.ne
+      (f64.const -1)
+      (local.get $fx)
+    ))
+    (drop (f64.lt
+      (f64.const -2)
+      (local.get $fx)
+    ))
+    (drop (f64.ge
+      (f64.const inf)
+      (local.get $fx)
+    ))
+    (drop (f64.le
+      (f64.const nan)
+      (local.get $fx)
+    ))
+    ;; skip
+    (drop (f64.ge
+      (f64.const 1)
+      (f64.const 2)
+    ))
+    (drop (i32.add (i32.ctz (local.get $x)) (i32.ctz (local.get $y))))
+    (drop (i32.add (i32.ctz (local.get $y)) (i32.ctz (local.get $x))))
+    (drop (i32.add (i32.ctz (local.get $x)) (i32.eqz (local.get $y))))
+    (drop (i32.add (i32.eqz (local.get $x)) (i32.ctz (local.get $y))))
+  )
+  (func $ne0 (result i32)
+    (if (i32.ne (call $ne0) (i32.const 0))
+      (nop)
+    )
+    (if (i32.ne (i32.const 0) (call $ne0))
+      (nop)
+    )
+    ;; through an or
+    (if
+      (i32.or
+        (i32.ne (i32.const 0) (call $ne0))
+        (i32.ne (i32.const 0) (call $ne0))
+      )
+      (nop)
+    )
+    ;; but not an and
+    (if
+      (i32.and
+        (i32.ne (i32.const 0) (call $ne0))
+        (i32.ne (i32.const 0) (call $ne0))
+      )
+      (nop)
+    )
+    (i32.const 1)
+  )
+  (func $recurse-bool
+    (if
+      (if (result i32)
+        (i32.const 1)
+        (i32.ne (call $ne0) (i32.const 0))
+        (i32.ne (call $ne1) (i32.const 0))
+      )
+      (nop)
+    )
+    (if
+      (block (result i32)
+        (nop)
+        (i32.ne (call $ne0) (i32.const 0))
+      )
+      (nop)
+    )
+  )
+  (func $ne1 (result i32)
+    (unreachable)
+  )
+  (func $load-off-2 "load-off-2" (param $0 i32) (result i32)
+    (i32.store offset=2
+      (i32.add
+        (i32.const 1)
+        (i32.const 3)
+      )
+      (local.get $0)
+    )
+    (i32.store offset=2
+      (i32.add
+        (i32.const 3)
+        (i32.const 1)
+      )
+      (local.get $0)
+    )
+    (i32.store offset=2
+      (i32.add
+        (local.get $0)
+        (i32.const 5)
+      )
+      (local.get $0)
+    )
+    (i32.store offset=2
+      (i32.add
+        (i32.const 7)
+        (local.get $0)
+      )
+      (local.get $0)
+    )
+    (i32.store offset=2
+      (i32.add
+        (i32.const -11) ;; do not fold this!
+        (local.get $0)
+      )
+      (local.get $0)
+    )
+    (i32.store offset=2
+      (i32.add
+        (local.get $0)
+        (i32.const -13) ;; do not fold this!
+      )
+      (local.get $0)
+    )
+    (i32.store offset=2
+      (i32.add
+        (i32.const -15)
+        (i32.const 17)
+      )
+      (local.get $0)
+    )
+    (i32.store offset=2
+      (i32.add
+        (i32.const -21)
+        (i32.const 19)
+      )
+      (local.get $0)
+    )
+    (i32.store offset=2
+      (i32.const 23)
+      (local.get $0)
+    )
+    (i32.store offset=2
+      (i32.const -25)
+      (local.get $0)
+    )
+    (drop
+      (i32.load offset=2
+        (i32.add
+          (i32.const 2)
+          (i32.const 4)
+        )
+      )
+    )
+    (drop
+      (i32.load offset=2
+        (i32.add
+          (i32.const 4)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.load offset=2
+        (i32.add
+          (local.get $0)
+          (i32.const 6)
+        )
+      )
+    )
+    (drop
+      (i32.load offset=2
+        (i32.const 8)
+      )
+    )
+    (i32.load offset=2
+      (i32.add
+        (i32.const 10)
+        (local.get $0)
+      )
+    )
+  )
+  (func $sign-ext (param $0 i32) (param $1 i32)
+    ;; eq of sign-ext to const, can be a zext
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 16)
+          )
+          (i32.const 16)
+        )
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 5) ;; weird size, but still valid
+          )
+          (i32.const 5)
+        )
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 100) ;; non-zero
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 32767) ;; non-zero and bigger than the mask, with sign bit
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const -149) ;; non-zero and bigger than the mask, without sign bit
+      )
+    )
+    ;; eq of two sign-ext, can both be a zext
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.shr_s
+          (i32.shl
+            (local.get $1)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 16)
+          )
+          (i32.const 16)
+        )
+        (i32.shr_s
+          (i32.shl
+            (local.get $1)
+            (i32.const 16)
+          )
+          (i32.const 16)
+        )
+      )
+    )
+    ;; corner cases we should not opt
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 23) ;; different shift, smaller
+        )
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_u ;; unsigned
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.lt_s ;; non-eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 0)
+      )
+    )
+    (drop
+      (if (result i32)
+        (i32.shr_s
+          (i32.shl
+            (unreachable) ;; ignore an unreachable value
+            (i32.const 16)
+          )
+          (i32.const 16)
+        )
+        (i32.const 111)
+        (i32.const 222)
+      )
+    )
+  )
+  (func $sign-ext-input (param $0 i32) (param $1 i32)
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.const 100) ;; small!
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.const 127) ;; just small enough
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.const 128) ;; just too big
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $0) ;; who knows...
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (unreachable) ;; ignore
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.div_s ;; this could be optimizable in theory, but currently we don't look into adds etc.
+            (i32.const 1)
+            (i32.const 2)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.and ;; takes the min, here it is ok
+            (i32.const 127)
+            (i32.const 128)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.and ;; takes the min, here it is not
+            (i32.const 128)
+            (i32.const 129)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.xor ;; takes the max, here it is ok
+            (i32.const 127)
+            (i32.const 126)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.xor ;; takes the max, here it is not
+            (i32.const 127)
+            (i32.const 128)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.or ;; takes the max, here it is ok
+            (i32.const 127)
+            (i32.const 126)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.or ;; takes the max, here it is not
+            (i32.const 127)
+            (i32.const 128)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shl ;; adds, here it is too much
+            (i32.const 32)
+            (i32.const 2)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shl ;; adds, here it is ok
+            (i32.const 32)
+            (i32.const 1)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shl ;; adds, here it is too much and "overflows"
+            (i32.const 32)
+            (i32.const 35)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_u ;; subtracts, here it is still too much
+            (i32.const 256)
+            (i32.const 1)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_u ;; subtracts, here it is ok
+            (i32.const 256)
+            (i32.const 2)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_u ;; subtracts, here it "overflows"
+            (i32.const 128)
+            (i32.const 35)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_s ;; subtracts, here it is still too much
+            (i32.const 256)
+            (i32.const 1)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_s ;; subtracts, here it is ok
+            (i32.const 256)
+            (i32.const 2)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_s ;; subtracts, here it "overflows"
+            (i32.const 128)
+            (i32.const 35)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_s ;; subtracts, here there is a sign bit, so it stays 32 bits no matter how much we shift
+            (i32.const -1)
+            (i32.const 32)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_s ;; subtracts, here we mask out that sign bit
+            (i32.and
+              (i32.const -1)
+              (i32.const 2147483647)
+            )
+            (i32.const 31) ;; adjusted after we fixed shift computation to just look at lower 5 bits
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.ne ;; 1 bit
+            (i32.const -1)
+            (i32.const -1)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (f32.le
+            (f32.const -1)
+            (f32.const -1)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.clz ;; assumed 5 bits
+            (i32.const 0)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shl
+            (i32.clz ;; assumed 5 bits
+              (i32.const 0)
+            )
+            (i32.const 2) ;; + 2, so 7
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shl
+            (i32.clz ;; assumed 5 bits
+              (i32.const 0)
+            )
+            (i32.const 3) ;; + 3, so 8, too much
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.wrap_i64 ;; preserves 6
+            (i64.clz ;; assumed 6 bits
+              (i64.const 0)
+            )
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shl
+            (i32.wrap_i64 ;; preserves 6
+              (i64.clz ;; assumed 6 bits
+                (i64.const 0)
+              )
+            )
+            (i32.const 1) ;; + 1, so 7
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shl
+            (i32.wrap_i64 ;; preserves 6
+              (i64.clz ;; assumed 6 bits
+                (i64.const 0)
+              )
+            )
+            (i32.const 2) ;; + 2, so 8, too much
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.eqz ;; 1 bit
+            (i32.const -1)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_u
+            (i32.wrap_i64 ;; down to 32
+              (i64.const -1) ;; 64
+            )
+            (i32.const 24) ;; 32 - 24 = 8
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_u
+            (i32.wrap_i64 ;; down to 32
+              (i64.const -1) ;; 64
+            )
+            (i32.const 25) ;; 32 - 25 = 7, ok
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_u
+            (i32.wrap_i64 ;; stay 32
+              (i64.extend_i32_s
+                (i32.const -1)
+              )
+            )
+            (i32.const 24) ;; 32 - 24 = 8
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_u
+            (i32.wrap_i64 ;; stay 32
+              (i64.extend_i32_s
+                (i32.const -1)
+              )
+            )
+            (i32.const 25) ;; 32 - 25 = 7, ok
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop ;; fuzz testcase
+      (i32.shr_s
+        (i32.shl
+          (i32.xor ;; should be 32 bits
+            (i32.le_u ;; 1 bit
+              (local.get $0)
+              (i32.const 2)
+            )
+            (local.get $0) ;; unknown, so 32 bits
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $linear-sums (param $0 i32) (param $1 i32)
+    (drop
+      (i32.add
+        (i32.add
+          (local.get $1)
+          (i32.const 16)
+        )
+        (i32.shl
+          (i32.add
+            (local.get $0)
+            (i32.const -1) ;; -16, so cancels out!
+          )
+          (i32.const 4)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.add
+          (local.get $1)
+          (i32.const 20)
+        )
+        (i32.shl
+          (i32.add
+            (local.get $0)
+            (i32.const -1) ;; -8, so sum is +12
+          )
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.add ;; simple sum
+        (i32.const 1)
+        (i32.const 3)
+      )
+    )
+    (drop
+      (i32.add ;; nested sum
+        (i32.add
+          (i32.const 1)
+          (i32.const 3)
+        )
+        (i32.add
+          (i32.const 5)
+          (i32.const 9)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.add
+          (i32.const 1)
+          (i32.const 3)
+        )
+        (i32.sub ;; internal sub
+          (i32.const 5)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.sub ;; external sub
+        (i32.add
+          (i32.const 1)
+          (i32.const 3)
+        )
+        (i32.add
+          (i32.const 5)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.sub ;; external sub
+        (i32.add
+          (i32.const 1)
+          (i32.const 3)
+        )
+        (i32.sub ;; and also internal sub
+          (i32.const 5)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.add
+          (i32.const 1)
+          (i32.const 3)
+        )
+        (i32.sub ;; negating sub
+          (i32.const 0)
+          (i32.const 3)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.sub
+          (i32.const 0)
+          (i32.sub ;; two negating subs
+            (i32.const 0)
+            (i32.add
+              (i32.const 3)
+              (i32.const 20)
+            )
+          )
+        )
+        (i32.add
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.add
+          (i32.const 0)
+          (i32.sub ;; one negating sub
+            (i32.const 0)
+            (i32.add
+              (i32.const 3)
+              (i32.const 20)
+            )
+          )
+        )
+        (i32.add
+          (i32.const 1)
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.shl ;; shifted value
+          (i32.const 1)
+          (i32.const 3)
+        )
+        (i32.add
+          (i32.const 5)
+          (i32.const 9)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.shl ;; shifted value
+          (i32.const 1)
+          (local.get $0) ;; but not by const
+        )
+        (i32.add
+          (i32.const 5)
+          (i32.const 9)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.shl ;; shifted nested value
+          (i32.sub
+            (local.get $1)
+            (i32.const 10)
+          )
+          (i32.const 3)
+        )
+        (i32.add
+          (i32.const 5)
+          (i32.const 9)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.mul ;; multiplied
+          (i32.const 10)
+          (i32.const 3)
+        )
+        (i32.add
+          (i32.const 5)
+          (i32.const 9)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.mul ;; multiplied by nonconstant - can't recurse
+          (i32.const 10)
+          (local.get $0)
+        )
+        (i32.add
+          (i32.const 5)
+          (i32.const 9)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.mul ;; nested mul
+          (i32.add
+            (i32.const 10)
+            (local.get $0)
+          )
+          (i32.const 2)
+        )
+        (i32.add
+          (i32.const 5)
+          (i32.const 9)
+        )
+      )
+    )
+    (drop
+      (i32.add
+        (i32.add
+          (local.get $0)
+          (i32.const 10) ;; cancelled out with the below
+        )
+        (i32.sub
+          (i32.const -5)
+          (i32.const 5)
+        )
+      )
+    )
+  )
+  (func $almost-sign-ext (param $0 i32)
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.const 100) ;; too big, there is a sign bit, due to the extra shift
+          (i32.const 25)
+        )
+        (i32.const 24) ;; different shift, but larger, so ok to opt if we leave a shift, in theory
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.const 50) ;; small enough, no sign bit
+          (i32.const 25)
+        )
+        (i32.const 24) ;; different shift, but larger, so ok to opt if we leave a shift
+      )
+    )
+  )
+  (func $squaring (param $0 i32) (param $1 i32)
+    (drop
+      (i32.and
+        (i32.and
+          (local.get $0)
+          (i32.const 11)
+        )
+        (i32.const 200)
+      )
+    )
+    (drop
+      (i32.and
+        (i32.and
+          (local.get $0)
+          (i32.const 11)
+        )
+        (local.get $0) ;; non-const, cannot optimize this!
+      )
+    )
+    (drop
+      (i32.and
+        (i32.and
+          (i32.const 11) ;; flipped order
+          (local.get $0)
+        )
+        (i32.const 200)
+      )
+    )
+    (drop
+      (i32.or
+        (i32.or
+          (local.get $0)
+          (i32.const 11)
+        )
+        (i32.const 200)
+      )
+    )
+    (drop
+      (i32.shl
+        (i32.shl
+          (local.get $0)
+          (i32.const 11)
+        )
+        (i32.const 200)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shr_s
+          (local.get $0)
+          (i32.const 11)
+        )
+        (i32.const 200)
+      )
+    )
+    (drop
+      (i32.shr_u
+        (i32.shr_u
+          (local.get $0)
+          (i32.const 11)
+        )
+        (i32.const 200)
+      )
+    )
+    (drop
+      (i32.shr_u
+        (i32.shr_s ;; but do not optimize a mixture or different shifts!
+          (local.get $0)
+          (i32.const 11)
+        )
+        (i32.const 200)
+      )
+    )
+  )
+  (func $sign-ext-ne (param $0 i32) (param $1 i32)
+    ;; ne of sign-ext to const, can be a zext
+    (drop
+      (i32.ne
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 65000)
+      )
+    )
+    (drop
+      (i32.ne
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 64872) ;; no sign bit
+      )
+    )
+    (drop
+      (i32.ne
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const -149) ;; no sign bit, not all ones
+      )
+    )
+    (drop
+      (i32.ne
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 111)
+      )
+    )
+    (drop
+      (i32.ne
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.shr_s
+          (i32.shl
+            (local.get $1)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+      )
+    )
+  )
+  (func $sign-ext-eqz (param $0 i32) (param $1 i32)
+    (drop
+      (i32.eqz
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+      )
+    )
+  )
+  (func $sign-ext-boolean (param $0 i32) (param $1 i32)
+    (drop
+      (if (result i32)
+        (i32.shr_s
+          (i32.shl
+            (local.get $0)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 100)
+        (i32.const 200)
+      )
+    )
+  )
+  (func $add-sub-zero (param $0 i32) (param $1 i64)
+    (drop
+      (i32.add
+        (local.get $0)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.sub
+        (local.get $0)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i64.add
+        (local.get $1)
+        (i64.const 0)
+      )
+    )
+    (drop
+      (i64.sub
+        (local.get $1)
+        (i64.const 0)
+      )
+    )
+  )
+  (func $store-signext (param $0 i32)
+    (i32.store8
+      (i32.const 8)
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 24) ;; exact size we store, sign-ext of 8 bits
+        )
+        (i32.const 24)
+      )
+    )
+    (i32.store8
+      (i32.const 8)
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 25) ;; 7 bits. so the ext can alter a bit we store, do not optimize
+        )
+        (i32.const 25)
+      )
+    )
+    (i32.store8
+      (i32.const 8)
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 23) ;; 9 bits, this is good to optimize
+        )
+        (i32.const 23)
+      )
+    )
+    (i32.store16
+      (i32.const 8)
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 16) ;; exact size we store, sign-ext of 16 bits
+        )
+        (i32.const 16)
+      )
+    )
+    (i32.store16
+      (i32.const 8)
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 17) ;; 15 bits. so the ext can alter a bit we store, do not optimize
+        )
+        (i32.const 17)
+      )
+    )
+    (i32.store16
+      (i32.const 8)
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 14) ;; 17 bits, this is good to optimize
+        )
+        (i32.const 14)
+      )
+    )
+    (i32.store
+      (i32.const 8)
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 16) ;; 4 bytes stored, do nothing
+        )
+        (i32.const 16)
+      )
+    )
+    (i32.store
+      (i32.const 8)
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 8) ;; 4 bytes stored, do nothing
+        )
+        (i32.const 8)
+      )
+    )
+  )
+  (func $sign-ext-tee (param $0 i32) (param $1 i32)
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.tee $0
+            (i32.const 128) ;; too big
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.tee $0
+            (i32.const 127) ;; just right
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $sign-ext-load (param $0 i32) (param $1 i32)
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.load8_s ;; one byte, so perfect
+            (i32.const 256)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_u
+            (i32.load8_s ;; one byte, but sexted to 32
+              (i32.const 256)
+            )
+            (i32.const 1)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shr_u
+            (i32.load8_u ;; one byte, but reduced to 7
+              (i32.const 256)
+            )
+            (i32.const 1)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.load16_s ;; two, so perfect
+            (i32.const 256)
+          )
+          (i32.const 16)
+        )
+        (i32.const 16)
+      )
+    )
+    ;; through tees, we cannot alter the load sign
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.tee $1
+            (i32.load8_s
+              (i32.const 1)
+            )
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.tee $1
+            (i32.load8_u
+              (i32.const 1)
+            )
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.and
+        (local.tee $1
+          (i32.load8_s
+            (i32.const 1)
+          )
+        )
+        (i32.const 255)
+      )
+    )
+    (drop
+      (i32.and
+        (local.tee $1
+          (i32.load8_u
+            (i32.const 1)
+          )
+        )
+        (i32.const 255)
+      )
+    )
+  )
+  (func $mask-bits (param $0 i32) (param $1 i32)
+    (drop
+      (i32.and
+        (local.tee $0
+          (i32.const 127) ;; 7 bits
+        )
+        (i32.const 255) ;; mask 8, so we don't need this
+      )
+    )
+    (drop
+      (i32.and
+        (local.tee $0
+          (i32.const 128) ;; 8 bits
+        )
+        (i32.const 255) ;; mask 8, so we don't need this
+      )
+    )
+    (drop
+      (i32.and
+        (local.tee $0
+          (i32.const 128)
+        )
+        (i32.const 254) ;; improper mask, small
+      )
+    )
+    (drop
+      (i32.and
+        (local.tee $0
+          (i32.const 128)
+        )
+        (i32.const 1279) ;; improper mask, large
+      )
+    )
+    (drop
+      (i32.and
+        (local.tee $0
+          (i32.const 128)
+        )
+        (i32.const 1290) ;; improper mask, large
+      )
+    )
+    (drop
+      (i32.and
+        (local.tee $0
+          (i32.const 128)
+        )
+        (i32.const 4095) ;; proper mask, huge
+      )
+    )
+    (drop
+      (i32.and
+        (local.tee $0
+          (i32.const 128)
+        )
+        (i32.const 511) ;; proper mask, large
+      )
+    )
+    (drop
+      (i32.and
+        (local.tee $0
+          (i32.const 128)
+        )
+        (i32.const 127) ;; proper mask, just too small
+      )
+    )
+  )
+  (func $local-info-zero-ext (param $0 i32) (param $1 i32)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $w i32)
+    (local.set $x
+      (i32.const 212) ;; mask is unneeded, we are small
+    )
+    (drop
+      (i32.and
+        (local.get $x)
+        (i32.const 255)
+      )
+    )
+    (local.set $y
+      (i32.const 500) ;; mask is needed, we are too big
+    )
+    (drop
+      (i32.and
+        (local.get $y)
+        (i32.const 255)
+      )
+    )
+    (local.set $0
+      (i32.const 212) ;; mask is unneeded, but we are a param, not a var, so no
+    )
+    (drop
+      (i32.and
+        (local.get $0)
+        (i32.const 255)
+      )
+    )
+    (local.set $z
+      (i32.const 212) ;; mask is unneeded, we are small
+    )
+    (local.set $z
+      (i32.const 220) ;; mask is still unneeded even with 2 uses
+    )
+    (drop
+      (i32.and
+        (local.get $z)
+        (i32.const 255)
+      )
+    )
+    (local.set $w
+      (i32.const 212) ;; mask is unneeded, we are small
+    )
+    (local.set $w
+      (i32.const 1000) ;; mask is needed, one use is too big
+    )
+    (drop
+      (i32.and
+        (local.get $w)
+        (i32.const 255)
+      )
+    )
+  )
+  (func $local-info-sign-ext-bitsize (param $0 i32) (param $1 i32)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $w i32)
+    (local.set $x
+      (i32.const 127) ;; mask is unneeded, we are small
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $x)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $y
+      (i32.const 128) ;; mask is needed, we are too big
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $y)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $0
+      (i32.const 127) ;; mask is unneeded, but we are a param, not a var, so no
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $z
+      (i32.const 127) ;; mask is unneeded, we are small
+    )
+    (local.set $z
+      (i32.const 100) ;; mask is still unneeded even with 2 uses
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $z)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $w
+      (i32.const 127) ;; mask is unneeded, we are small
+    )
+    (local.set $w
+      (i32.const 150) ;; mask is needed, one use is too big
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $w)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $local-info-sign-ext-already-exted (param $0 i32) (param $1 i32)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $w i32)
+    (local.set $x
+      (i32.shr_s
+        (i32.shl
+          (local.get $0) ;; already sign-exted here, so no need later
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $x)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $y
+      (i32.shr_s
+        (i32.shl
+          (local.get $0) ;; already sign-exted here, but wrong bit size
+          (i32.const 16)
+        )
+        (i32.const 16)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $y)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $0
+      (i32.shr_s
+        (i32.shl
+          (local.get $0) ;; already sign-exted here, so no need later, but we are a param
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $0)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $z
+      (i32.shr_s
+        (i32.shl
+          (local.get $0) ;; already sign-exted here, so no need later
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $z
+      (i32.shr_s
+        (i32.shl
+          (local.get $1) ;; already sign-exted here, so no need later
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $z)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $w
+      (i32.shr_s
+        (i32.shl
+          (local.get $0) ;; already sign-exted here, so no need later
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $w
+      (i32.shr_s
+        (i32.shl
+          (local.get $0) ;; not quite a sign-ext
+          (i32.const 23)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $w)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (drop ;; odd corner case
+      (i32.shr_s
+        (i32.shl
+          (local.get $0) ;; param, so we should know nothing
+          (i32.const 24)
+        )
+        (i32.const 23) ;; different shift, smaller
+      )
+    )
+  )
+  (func $signed-loads-fill-the-bits (param $$e i32) (result i32)
+    (local $$0 i32)
+    (local $$conv i32)
+    (local.set $$0
+      (i32.load8_s ;; one byte, but 32 bits due to sign-extend
+        (i32.const 1024)
+      )
+    )
+    (local.set $$conv
+      (i32.and
+        (local.get $$0)
+        (i32.const 255) ;; so we need this zexting!
+      )
+    )
+    (return
+      (i32.eq
+        (local.get $$conv)
+        (local.get $$e)
+      )
+    )
+  )
+  (func $local-info-sign-ext-already-exted-by-load (param $0 i32) (param $1 i32)
+    (local $x i32)
+    (local $y i32)
+    (local $z i32)
+    (local $w i32)
+    (local.set $x
+      (i32.load8_s (i32.const 1024)) ;; 8 bits, sign extended, no need to do it again
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $x)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $y
+      (i32.load8_u (i32.const 1024)) ;; 8 bits, zext, so bad
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $y)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+    (local.set $z
+      (i32.load16_s (i32.const 1024)) ;; 16 bits sign-extended, wrong size
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (local.get $z)
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $compare-load-s-sign-extend (param $0 i32) (param $1 i32)
+    (drop
+      (i32.eq
+        (i32.load8_s
+          (local.get $0)
+        )
+        (i32.shr_s
+          (i32.shl
+            (local.get $1)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $1)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.load8_s
+          (local.get $0) ;; flip order, we should canonicalize
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.load8_u ;; unsigned, bad
+          (local.get $0)
+        )
+        (i32.shr_s
+          (i32.shl
+            (local.get $1)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.load8_s
+          (local.get $0)
+        )
+        (i32.shr_s
+          (i32.shl
+            (local.get $1)
+            (i32.const 16) ;; wrong size
+          )
+          (i32.const 16)
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $1)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.load8_u ;; unsigned, bad
+          (local.get $0)
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $1)
+            (i32.const 16) ;; wrong size
+          )
+          (i32.const 16)
+        )
+        (i32.load8_s
+          (local.get $0)
+        )
+      )
+    )
+  )
+  (func $unsign-diff-sizes (param $x i32) (param $y i32) (result i32)
+    (i32.ne
+      (i32.shr_s
+        (i32.shl
+          (call $unsign-diff-sizes
+            (i32.const -1)
+            (i32.const 5)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+      (i32.shr_s
+        (i32.shl
+          (call $unsign-diff-sizes
+            (i32.const 1)
+            (i32.const 2006)
+          )
+          (i32.const 16)
+        )
+        (i32.const 16)
+      )
+    )
+  )
+  (func $unsign-same-sizes (param $x i32) (param $y i32) (result i32)
+    (i32.ne
+      (i32.shr_s
+        (i32.shl
+          (call $unsign-same-sizes
+            (i32.const -1)
+            (i32.const 5)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+      (i32.shr_s
+        (i32.shl
+          (call $unsign-same-sizes
+            (i32.const 1)
+            (i32.const 2006)
+          )
+          (i32.const 24)
+        )
+        (i32.const 24)
+      )
+    )
+  )
+  (func $fuzz-almost-sign-ext
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.load16_u
+            (i32.const 2278)
+          )
+          (i32.const 17)
+        )
+        (i32.const 16)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.shl
+          (i32.shl
+            (i32.load16_u
+              (i32.const 2278)
+            )
+            (i32.const 1)
+          )
+          (i32.const 16)
+        )
+        (i32.const 16)
+      )
+    )
+  )
+  (func $fuzz-comp-impossible (param $x i32)
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $x)
+            (i32.const 16)
+          )
+          (i32.const 16)
+        )
+        (i32.const 65535) ;; impossible to be equal, the effective sign bit is set, but not the higher bits, which the sign-ext will set on the non-const value
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $x)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 255)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $x)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 127) ;; safe
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $x)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 128) ;; unsafe again
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $x)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 4223) ;; more big bits, so sign bit though
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $x)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const 4224) ;; more big bits
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.shr_s
+          (i32.shl
+            (local.get $x)
+            (i32.const 24)
+          )
+          (i32.const 24)
+        )
+        (i32.const -4) ;; safe even with more big bits, as they are all 1s
+      )
+    )
+  )
+  (func $if-parallel (param $0 i32) (param $1 i32)
+    (drop
+      (if (result i32)
+        (local.get $0)
+        (i32.add (local.get $1) (i32.const 1))
+        (i32.add (local.get $1) (i32.const 1))
+      )
+    )
+    (drop
+      (if (result i32)
+        (local.tee $0 (local.get $1)) ;; side effects!
+        (i32.add (local.get $1) (i32.const 1))
+        (i32.add (local.get $1) (i32.const 1))
+      )
+    )
+    (drop
+      (if (result i32)
+        (local.get $0)
+        (i32.add (local.get $1) (unreachable)) ;; folding them would change the type of the if
+        (i32.add (local.get $1) (unreachable))
+      )
+    )
+    (drop
+      (if (result i32)
+        (local.tee $0 (local.get $1)) ;; side effects!
+        (i32.add (local.get $1) (unreachable)) ;; folding them would change the type of the if
+        (i32.add (local.get $1) (unreachable))
+      )
+    )
+    (drop
+      (if (result i32)
+        (unreachable) ;; !!!
+        (i32.add (local.get $1) (unreachable)) ;; folding them would change the type of the if
+        (i32.add (local.get $1) (unreachable))
+      )
+    )
+  )
+  (func $select-parallel (param $0 i32) (param $1 i32)
+    (drop
+      (select
+        (i32.add (local.get $1) (i32.const 1))
+        (i32.add (local.get $1) (i32.const 1))
+        (local.get $0)
+      )
+    )
+    (drop
+      (select
+        (local.tee $0 (local.get $1)) ;; side effects!
+        (local.tee $0 (local.get $1)) ;; side effects!
+        (local.get $0)
+      )
+    )
+    (drop
+      (select
+        (i32.add (local.get $1) (i32.const 1))
+        (i32.add (local.get $1) (i32.const 1))
+        (local.tee $0 (local.get $1)) ;; side effects! (but no interference with values)
+      )
+    )
+    (drop
+      (select
+        (local.tee $0 (local.get $1)) ;; side effects! interference!
+        (local.tee $0 (local.get $1)) ;; side effects! interference!
+        (local.tee $0 (local.get $1)) ;; side effects! interference!
+      )
+    )
+    (drop
+      (select
+        (local.tee $0 (local.get $1)) ;; side effects!
+        (local.tee $0 (local.get $1)) ;; side effects!
+        (unreachable) ;; side effects! (but no interference with values)
+      )
+    )
+  )
+  (func $zero-shifts-is-not-sign-ext
+   (drop
+    (i32.eq
+     (i32.const -5431187)
+     (i32.add
+      (i32.const 0)
+      (i32.shr_s
+       (i32.shl
+        (i32.load16_s align=1
+         (i32.const 790656516)
+        )
+        (i32.const 0)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+   )
+   (drop
+    (i32.eq
+     (i32.const -5431187)
+     (i32.add
+      (i32.const 0)
+      (i32.shr_s
+       (i32.shl
+        (i32.load16_s align=1
+         (i32.const 790656516)
+        )
+        (i32.const 1)
+       )
+       (i32.const 0)
+      )
+     )
+    )
+   )
+  )
+  (func $zero-ops (result i32)
+   (return
+    (i32.eq
+     (i32.const -1337)
+     (i32.shr_u
+      (i32.add
+       (i32.const 0)
+       (i32.shr_s
+        (i32.shl
+         (i32.load16_s align=1
+          (i32.const 790656516)
+         )
+         (i32.const 0)
+        )
+        (i32.const 0)
+       )
+      )
+      (i32.const 0)
+     )
+    )
+   )
+  )
+  (func $zero-ops-64 (result i32)
+   (return
+    (i64.eq
+     (i64.const -1337)
+     (i64.shr_u
+      (i64.add
+       (i64.const 0)
+       (i64.shr_s
+        (i64.shl
+         (i64.load16_s align=1
+          (i32.const 790656516)
+         )
+         (i64.const 0)
+        )
+        (i64.const 0)
+       )
+      )
+      (i64.const 0)
+     )
+    )
+   )
+  )
+  (func $zero-ops-64-special (result i32)
+    (return
+      (i32.wrap_i64
+        (i64.popcnt
+          (i64.sub
+            (i64.shl
+              (i64.const 4294783828)
+              (i64.const 17179869183)
+            )
+            (i64.const -7377)
+          )
+        )
+      )
+    )
+  )
+  (func $sign-ext-1-and-ne (result i32)
+   (select
+    (i32.ne
+     (i32.const 1333788672)
+     (i32.shr_s
+      (i32.shl
+       (call $sign-ext-1-and-ne)
+       (i32.const 1)
+      )
+      (i32.const 1)
+     )
+    )
+    (i32.const 2)
+    (i32.const 1)
+   )
+  )
+  (func $neg-shifts-and-255 (result i32)
+    (i32.and
+     (i32.shr_u
+      (i32.const -99)
+      (i32.const -32) ;; this shift does nothing
+     )
+     (i32.const 255)
+    )
+  )
+  (func $neg-shifts-and-255-b (result i32)
+   (i32.and
+    (i32.shl
+     (i32.const -2349025)
+     (i32.const -32) ;; this shift does nothing
+    )
+    (i32.const 255)
+   )
+  )
+  (func $shifts-square-overflow (param $x i32) (result i32)
+   (i32.shr_u
+    (i32.shr_u
+     (local.get $x)
+     (i32.const 65535) ;; 31 bits effectively
+    )
+    (i32.const 32767) ;; also 31 bits, so two shifts that force the value into nothing for sure
+   )
+  )
+  (func $shifts-square-no-overflow-small (param $x i32) (result i32)
+   (i32.shr_u
+    (i32.shr_u
+     (local.get $x)
+     (i32.const 1031) ;; 7 bits effectively
+    )
+    (i32.const 4098) ;; 2 bits effectively
+   )
+  )
+  (func $shifts-square-overflow-64 (param $x i64) (result i64)
+   (i64.shr_u
+    (i64.shr_u
+     (local.get $x)
+     (i64.const 65535) ;; 63 bits effectively
+    )
+    (i64.const 64767) ;; also 63 bits, so two shifts that force the value into nothing for sure
+   )
+  )
+  (func $shifts-square-no-overflow-small-64 (param $x i64) (result i64)
+   (i64.shr_u
+    (i64.shr_u
+     (local.get $x)
+     (i64.const 1031) ;; 7 bits effectively
+    )
+    (i64.const 4098) ;; 2 bits effectively
+   )
+  )
+  (func $shifts-square-unreachable (param $x i32) (result i32)
+   (i32.shr_u
+    (i32.shr_u
+     (unreachable)
+     (i32.const 1031) ;; 7 bits effectively
+    )
+    (i32.const 4098) ;; 2 bits effectively
+   )
+  )
+  (func $mix-shifts (result i32)
+    (i32.shr_s
+     (i32.shl
+      (i32.const 23)
+      (i32.const -61)
+     )
+     (i32.const 168)
+    )
+  )
+  (func $actually-no-shifts (result i32)
+    (i32.add
+      (i32.shl
+        (i32.const 23)
+        (i32.const 32) ;; really 0
+      )
+      (i32.const 10)
+    )
+  )
+  (func $less-shifts-than-it-seems (param $x i32) (result i32)
+    (i32.add
+      (i32.shl
+        (i32.const 200)
+        (i32.const 36) ;; really 4
+      )
+      (i32.shl
+        (i32.const 100)
+        (i32.const 4)
+      )
+    )
+  )
+  (func $and-popcount32 (result i32)
+    (i32.and
+      (i32.popcnt
+        (i32.const -1)
+      )
+      (i32.const 31)
+    )
+  )
+  (func $and-popcount32-big (result i32)
+    (i32.and
+      (i32.popcnt
+        (i32.const -1)
+      )
+      (i32.const 63)
+    )
+  )
+  (func $and-popcount64 (result i64) ;; these are TODOs
+    (i64.and
+      (i64.popcnt
+        (i64.const -1)
+      )
+      (i64.const 63)
+    )
+  )
+  (func $and-popcount64-big (result i64)
+    (i64.and
+      (i64.popcnt
+        (i64.const -1)
+      )
+      (i64.const 127)
+    )
+  )
+  (func $and-popcount64-bigger (result i64)
+    (i64.and
+      (i64.popcnt
+        (i64.const -1)
+      )
+      (i64.const 255)
+    )
+  )
+  (func $optimizeAddedConstants-filters-through-nonzero (result i32)
+   (i32.sub
+    (i32.add
+     (i32.shl
+      (i32.const -536870912)
+      (i32.wrap_i64
+       (i64.const 0)
+      )
+     )
+     (i32.const -32768)
+    )
+    (i32.const -1024)
+   )
+  )
+  (func $optimizeAddedConstants-filters-through-nonzero-b (result i32)
+   (i32.sub
+    (i32.add
+     (i32.shl
+      (i32.const -536870912)
+      (i32.wrap_i64
+       (i64.const -1)
+      )
+     )
+     (i32.const -32768)
+    )
+    (i32.const -1024)
+   )
+  )
+  (func $return-proper-value-from-shift-left-by-zero (result i32)
+   (if (result i32)
+    (i32.sub
+     (i32.add
+      (loop $label$0 (result i32)
+       (block $label$1
+        (br_if $label$1
+         (i32.shl
+          (i32.load
+           (i32.const 0)
+          )
+          (i32.const -31904) ;; really 0 shifts
+         )
+        )
+       )
+       (i32.const -62)
+      )
+      (i32.const 38)
+     )
+     (i32.const -2)
+    )
+    (i32.const 1)
+    (i32.const 0)
+   )
+  )
+  (func $de-morgan-2 (param $x i32) (param $y i32)
+    (drop
+      (i32.and (i32.eqz (local.get $x)) (i32.eqz (local.get $y)))
+    )
+    (drop
+      (i32.or (i32.eqz (local.get $x)) (i32.eqz (local.get $y)))
+    )
+    (drop
+      (i32.xor (i32.eqz (local.get $x)) (i32.eqz (local.get $y)))
+    )
+    (drop
+      (i32.and (i32.eqz (local.get $x)) (local.get $y))
+    )
+    (drop
+      (i32.and (local.get $x) (i32.eqz (local.get $y)))
+    )
+    (drop
+      (i32.and (i32.eqz (local.get $x)) (i32.wrap_i64 (i64.const 2)))
+    )
+    (drop
+      (i32.and (i32.wrap_i64 (i64.const 1)) (i32.eqz (local.get $y)))
+    )
+  )
+  (func $subzero1 (param $0 i32) (result i32)
+    (i32.add
+     (i32.sub
+      (i32.const 1)
+      (i32.clz
+       (local.get $0)
+      )
+     )
+     (i32.const 31)
+    )
+  )
+  (func $subzero2 (param $0 i32) (result i32)
+    (i32.add
+     (i32.const 31)
+     (i32.sub
+      (i32.const 1)
+      (i32.clz
+       (local.get $0)
+      )
+     )
+    )
+  )
+  (func $subzero3 (param $0 i32) (param $1 i32) (result i32)
+    (i32.add
+     (i32.sub
+      (i32.const 0)
+      (i32.clz
+       (local.get $0)
+      )
+     )
+     (local.get $1)
+    )
+  )
+  (func $subzero4 (param $0 i32) (param $1 i32) (result i32)
+    (i32.add
+     (local.get $0)
+     (i32.sub
+      (i32.const 0)
+      (i32.clz
+       (local.get $1)
+      )
+     )
+    )
+  )
+  (func $mul-32-power-2 (param $x i32) (result i32)
+    (drop
+      (call $mul-32-power-2
+        (i32.mul
+          (local.get $x)
+          (i32.const 4)
+        )
+      )
+    )
+    (drop
+      (call $mul-32-power-2
+        (i32.mul
+          (local.get $x)
+          (i32.const 5)
+        )
+      )
+    )
+    (drop
+      (call $mul-32-power-2
+        (i32.mul
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (call $mul-32-power-2
+        (i32.mul
+          (local.get $x)
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (call $mul-32-power-2
+        (i32.mul
+          (call $mul-32-power-2 (i32.const 123)) ;; side effects
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (call $mul-32-power-2
+        (i32.mul
+          (local.get $x)
+          (i32.const 0xffffffff)
+        )
+      )
+    )
+    (drop
+      (call $mul-32-power-2
+        (i32.mul
+          (local.get $x)
+          (i32.const 0x80000000)
+        )
+      )
+    )
+    (unreachable)
+  )
+    (func $mul-64-power-2 (param $x i64) (result i64)
+    (drop
+      (call $mul-64-power-2
+        (i64.mul
+          (local.get $x)
+          (i64.const 4)
+        )
+      )
+    )
+    (drop
+      (call $mul-64-power-2
+        (i64.mul
+          (local.get $x)
+          (i64.const 5)
+        )
+      )
+    )
+    (drop
+      (call $mul-64-power-2
+        (i64.mul
+          (local.get $x)
+          (i64.const 1)
+        )
+      )
+    )
+    (drop
+      (call $mul-64-power-2
+        (i64.mul
+          (local.get $x)
+          (i64.const 0)
+        )
+      )
+    )
+    (drop
+      (call $mul-64-power-2
+        (i64.mul
+          (call $mul-64-power-2 (i64.const 123)) ;; side effects
+          (i64.const 0)
+        )
+      )
+    )
+    (drop
+      (call $mul-64-power-2
+        (i64.mul
+          (local.get $x)
+          (i64.const 0xffffffffffffffff)
+        )
+      )
+    )
+    (drop
+      (call $mul-64-power-2
+        (i64.mul
+          (local.get $x)
+          (i64.const 0x8000000000000000)
+        )
+      )
+    )
+    (unreachable)
+  )
+  (func $div-32-power-2 (param $x i32) (result i32)
+    (drop
+      (call $div-32-power-2
+        (i32.div_u
+          (local.get $x)
+          (i32.const 4)
+        )
+      )
+    )
+    (drop
+      (call $div-32-power-2
+        (i32.div_u
+          (local.get $x)
+          (i32.const 5)
+        )
+      )
+    )
+    (drop
+      (call $div-32-power-2
+        (i32.div_u
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (call $div-32-power-2
+        (i32.div_u
+          (local.get $x)
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (call $div-32-power-2
+        (i32.div_u
+          (call $div-32-power-2 (i32.const 123)) ;; side effects
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (call $div-32-power-2
+        (i32.div_u
+          (local.get $x)
+          (i32.const 0xffffffff)
+        )
+      )
+    )
+    (drop
+      (call $div-32-power-2
+        (i32.div_u
+          (local.get $x)
+          (i32.const 0x80000000)
+        )
+      )
+    )
+    (unreachable)
+  )
+  (func $urem-32-power-2 (param $x i32) (result i32)
+    (drop
+      (call $urem-32-power-2
+        (i32.rem_u
+          (local.get $x)
+          (i32.const 4)
+        )
+      )
+    )
+    (drop
+      (call $urem-32-power-2
+        (i32.rem_u
+          (local.get $x)
+          (i32.const 5)
+        )
+      )
+    )
+    (drop
+      (call $urem-32-power-2
+        (i32.rem_u
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+    )
+    (drop
+      (call $urem-32-power-2
+        (i32.rem_u
+          (local.get $x)
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (call $urem-32-power-2
+        (i32.rem_u
+          (local.get $x)
+          (i32.const 0xffffffff)
+        )
+      )
+    )
+    (drop
+      (call $urem-32-power-2
+        (i32.rem_u
+          (local.get $x)
+          (i32.const 0x80000000)
+        )
+      )
+    )
+    ;; (unsigned)x % 1
+    (drop
+      (call $urem-32-power-2
+        (i32.rem_u
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+    )
+    (unreachable)
+  )
+  (func $fdiv-32-power-2 (param $x f32)
+    (drop (f32.div
+      (local.get $x)
+      (f32.const 2)
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const -2)
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const 4294967296)
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const 18446744073709551616)
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const 0x1p-126)
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const 0x1p+126)
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const -0x1p-126)
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const -0x1p+126)
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const 0x1p-127) ;; skip
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const 0x1p-127) ;; skip
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const 0) ;; skip
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const nan) ;; skip
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const inf) ;; skip
+    ))
+    (drop (f32.div
+      (local.get $x)
+      (f32.const -inf) ;; skip
+    ))
+  )
+  (func $fdiv-64-power-2 (param $x f64)
+    (drop (f64.div
+      (local.get $x)
+      (f64.const 2)
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const -2)
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const 4294967296)
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const 18446744073709551616)
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const 0x1p-1022)
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const 0x1p+1022)
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const -0x1p-1022)
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const -0x1p+1022)
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const 0x1p-1023) ;; skip
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const 0x1p+1023) ;; skip
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const 0) ;; skip
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const nan) ;; skip
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const inf) ;; skip
+    ))
+    (drop (f64.div
+      (local.get $x)
+      (f64.const -inf) ;; skip
+    ))
+  )
+  (func $srem-by-const (param $x i32) (param $y i64)
+    ;; (signed)x % 1
+    (drop (i32.rem_s
+      (local.get $x)
+      (i32.const 1)
+    ))
+    (drop (i64.rem_s
+      (local.get $y)
+      (i64.const 1)
+    ))
+    ;; (signed)x % 0x80000000 -> x & 0x7FFFFFFF
+    (drop (i32.rem_s
+      (local.get $x)
+      (i32.const 0x80000000)
+    ))
+    ;; (signed)x % 0x8000000000000000 -> x & 0x7FFFFFFFFFFFFFFF
+    (drop (i64.rem_s
+      (local.get $y)
+      (i64.const 0x8000000000000000)
+    ))
+  )
+  (func $srem-by-pot-eq-ne-zero (param $x i32) (param $y i64)
+    ;; eqz((signed)x % 4)
+    (drop (i32.eqz
+      (i32.rem_s
+        (local.get $x)
+        (i32.const 4)
+      )
+    ))
+    (drop (i64.eqz
+      (i64.rem_s
+        (local.get $y)
+        (i64.const 4)
+      )
+    ))
+    ;; eqz((signed)x % -4)
+    (drop (i32.eqz
+      (i32.rem_s
+        (local.get $x)
+        (i32.const -4)
+      )
+    ))
+    (drop (i64.eqz
+      (i64.rem_s
+        (local.get $y)
+        (i64.const -4)
+      )
+    ))
+    ;; (signed)x % 4 == 0
+    (drop (i32.eq
+      (i32.rem_s
+        (local.get $x)
+        (i32.const 4)
+      )
+      (i32.const 0)
+    ))
+    (drop (i64.eq
+      (i64.rem_s
+        (local.get $y)
+        (i64.const 2)
+      )
+      (i64.const 0)
+    ))
+    ;; (signed)x % -4 == 0
+    (drop (i32.eq
+      (i32.rem_s
+        (local.get $x)
+        (i32.const -4)
+      )
+      (i32.const 0)
+    ))
+    (drop (i64.eq
+      (i64.rem_s
+        (local.get $y)
+        (i64.const -4)
+      )
+      (i64.const 0)
+    ))
+    ;; (signed)x % 2 != 0
+    (drop (i32.ne
+      (i32.rem_s
+        (local.get $x)
+        (i32.const 2)
+      )
+      (i32.const 0)
+    ))
+    (drop (i64.ne
+      (i64.rem_s
+        (local.get $y)
+        (i64.const 2)
+      )
+      (i64.const 0)
+    ))
+    ;; (signed)x % -1 == 0  ->  0 == 0
+    (drop (i32.eq
+      (i32.rem_s
+        (local.get $x)
+        (i32.const -1)
+      )
+      (i32.const 0)
+    ))
+    ;; (signed)x % 0x80000000 == 0
+    (drop (i32.eq
+      (i32.rem_s
+        (local.get $x)
+        (i32.const 0x80000000)
+      )
+      (i32.const 0)
+    ))
+    ;; (signed)x % 0x80000000 != 0
+    (drop (i32.ne
+      (i32.rem_s
+        (local.get $x)
+        (i32.const 0x80000000)
+      )
+      (i32.const 0)
+    ))
+    ;; (signed)x % 0x8000000000000000 == 0
+    (drop (i64.eq
+      (i64.rem_s
+        (local.get $y)
+        (i64.const 0x8000000000000000)
+      )
+      (i64.const 0)
+    ))
+    ;; (signed)x % 0x8000000000000000 != 0
+    (drop (i64.ne
+      (i64.rem_s
+        (local.get $y)
+        (i64.const 0x8000000000000000)
+      )
+      (i64.const 0)
+    ))
+    ;;
+    (drop (i32.eq
+      (i32.rem_s
+        (local.get $x)
+        (i32.const 3) ;; skip
+      )
+      (i32.const 0)
+    ))
+    (drop (i64.eq
+      (i64.rem_s
+        (local.get $y)
+        (i64.const 3) ;; skip
+      )
+      (i64.const 0)
+    ))
+  )
+  (func $orZero (param $0 i32) (result i32)
+    (i32.or
+      (local.get $0)
+      (i32.const 0)
+    )
+  )
+  (func $andZero (param $0 i32) (result i32)
+    (drop
+      (i32.and
+        (local.get $0)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.and
+        (call $andZero (i32.const 1234)) ;; side effects
+        (i32.const 0)
+      )
+    )
+    (unreachable)
+  )
+  (func $abstract-additions (param $x32 i32) (param $x64 i64) (param $y32 f32) (param $y64 f64)
+    (drop
+      (i32.or
+        (i32.const 0)
+        (local.get $x32)
+      )
+    )
+    (drop
+      (i32.shl
+        (local.get $x32)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.shr_u
+        (local.get $x32)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (local.get $x32)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i64.or
+        (i64.const 0)
+        (local.get $x64)
+      )
+    )
+    (drop
+      (i64.shl
+        (local.get $x64)
+        (i64.const 0)
+      )
+    )
+    (drop
+      (i64.shr_u
+        (local.get $x64)
+        (i64.const 0)
+      )
+    )
+    (drop
+      (i64.shr_s
+        (local.get $x64)
+        (i64.const 0)
+      )
+    )
+    (drop
+      (i32.mul
+        (local.get $x32)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i64.mul
+        (local.get $x64)
+        (i64.const 0)
+      )
+    )
+    (drop
+      (f32.mul
+        (local.get $y32)
+        (f32.const 0)
+      )
+    )
+    (drop
+      (f64.mul
+        (local.get $y64)
+        (f64.const 0)
+      )
+    )
+    (drop
+      (i32.mul
+        (local.get $x32)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (i64.mul
+        (local.get $x64)
+        (i64.const 1)
+      )
+    )
+    (drop
+      (f32.mul
+        (local.get $y32)
+        (f32.const 1)
+      )
+    )
+    (drop
+      (f64.mul
+        (local.get $y64)
+        (f64.const 1)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $x32)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i64.and
+        (local.get $x64)
+        (i64.const 0)
+      )
+    )
+    (drop
+      (i32.and
+        (unreachable)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (i64.and
+        (unreachable)
+        (i64.const 0)
+      )
+    )
+    (drop
+      (i32.div_s
+        (local.get $x32)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (i32.div_u
+        (local.get $x32)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (i64.div_s
+        (local.get $x64)
+        (i64.const 1)
+      )
+    )
+    (drop
+      (i64.div_u
+        (local.get $x64)
+        (i64.const 1)
+      )
+    )
+    (drop
+      (f32.div
+        (local.get $y32)
+        (f32.const 1)
+      )
+    )
+    (drop
+      (f64.div
+        (local.get $y64)
+        (f64.const 1)
+      )
+    )
+    (drop
+      (f32.div
+        (local.get $y32)
+        (f32.const 1.2)
+      )
+    )
+    (drop
+      (i32.mul
+        (local.get $x32)
+        (i32.const -1)
+      )
+    )
+    (drop
+      (i64.mul
+        (local.get $x64)
+        (i64.const -1)
+      )
+    )
+    (drop
+      (f32.mul
+        (local.get $y32)
+        (f32.const -1)
+      )
+    )
+    (drop
+      (f64.mul
+        (local.get $y64)
+        (f64.const -1)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.add
+          (local.get $x32)
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+    )
+    (drop
+      (i32.le_u
+        (i32.add
+          (local.get $x32)
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.sub
+          (local.get $x32)
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+    )
+    (drop
+      (i64.eq
+        (i64.add
+          (local.get $x64)
+          (i64.const 10)
+        )
+        (i64.const 20)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.const 20)
+        (i32.add
+          (local.get $x32)
+          (i32.const 10)
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.add
+          (local.get $x32)
+          (i32.const 10)
+        )
+        (i32.add
+          (local.get $x32)
+          (i32.const 20)
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.sub
+          (local.get $x32)
+          (i32.const 10)
+        )
+        (i32.const 20)
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.add
+          (local.get $x32)
+          (i32.const 10)
+        )
+        (i32.sub
+          (local.get $x32)
+          (i32.const 20)
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.sub
+          (local.get $x32)
+          (i32.const 10)
+        )
+        (i32.add
+          (local.get $x32)
+          (i32.const 20)
+        )
+      )
+    )
+    (drop
+      (i32.eq
+        (i32.sub
+          (local.get $x32)
+          (i32.const 10)
+        )
+        (i32.sub
+          (local.get $x32)
+          (i32.const 20)
+        )
+      )
+    )
+    (drop
+      (i64.le_s
+        (i64.sub
+          (local.get $x64)
+          (i64.const 288230376151711744)
+        )
+        (i64.const 9223372036854775807)
+      )
+    )
+  )
+  (func $negatives-are-sometimes-better (param $x i32) (param $y i64) (param $z f32)
+    (drop (i32.add (local.get $x) (i32.const 0x40)))
+    (drop (i32.sub (local.get $x) (i32.const 0x40)))
+    (drop (i32.add (local.get $x) (i32.const 0x2000)))
+    (drop (i32.add (local.get $x) (i32.const 0x100000)))
+    (drop (i32.add (local.get $x) (i32.const 0x8000000)))
+
+    (drop (i64.add (local.get $y) (i64.const 0x40)))
+    (drop (i64.sub (local.get $y) (i64.const 0x40)))
+    (drop (i64.add (local.get $y) (i64.const 0x2000)))
+    (drop (i64.add (local.get $y) (i64.const 0x100000)))
+    (drop (i64.add (local.get $y) (i64.const 0x8000000)))
+
+    (drop (i64.add (local.get $y) (i64.const 0x400000000)))
+    (drop (i64.add (local.get $y) (i64.const 0x20000000000)))
+    (drop (i64.add (local.get $y) (i64.const 0x1000000000000)))
+    (drop (i64.add (local.get $y) (i64.const 0x80000000000000)))
+    (drop (i64.add (local.get $y) (i64.const 0x4000000000000000)))
+
+    (drop (f32.add (local.get $z) (f32.const 0x40)))
+  )
+  (func $shift-a-zero (param $x i32) (param $y i64) (param $z f32)
+    (drop
+      (i32.shl
+        (i32.const 0)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.shr_u
+        (i32.const 0)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.shr_s
+        (i32.const 0)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i64.shl
+        (i64.const 0)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i32.shl
+        (i32.const 0)
+        (unreachable)
+      )
+    )
+  )
+  (func $identical-siblings (param $x i32) (param $y i64) (param $z f64) (param $xx i32)
+    (drop
+      (i32.sub
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i64.sub
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (f64.sub
+        (local.get $z)
+        (local.get $z)
+      )
+    )
+    (drop
+      (i32.sub
+        (local.get $x)
+        (local.get $xx)
+      )
+    )
+    (drop
+      (i32.sub
+        (unreachable)
+        (unreachable)
+      )
+    )
+    (drop
+      (i32.add
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    ;; more ops
+    (drop
+      (i32.xor
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.ne
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.lt_s
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.lt_u
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.gt_s
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.gt_u
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.and
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.or
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.eq
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.le_s
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.le_u
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.ge_s
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i32.ge_u
+        (local.get $x)
+        (local.get $x)
+      )
+    )
+    (drop
+      (i64.xor
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.ne
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.lt_s
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.lt_u
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.gt_s
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.gt_u
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.and
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.or
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.eq
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.le_s
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.le_u
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.ge_s
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+    (drop
+      (i64.ge_u
+        (local.get $y)
+        (local.get $y)
+      )
+    )
+  )
+  (func $all_ones (param $x i32) (param $y i64)
+    (drop
+      (i32.and
+        (local.get $x)
+        (i32.const -1)
+      )
+    )
+    (drop
+      (i32.or
+        (local.get $x)
+        (i32.const -1)
+      )
+    )
+    (drop
+      (i32.or
+        (local.tee $x
+          (i32.const 1337)
+        )
+        (i32.const -1)
+      )
+    )
+    (drop
+      (i64.and
+        (local.get $y)
+        (i64.const -1)
+      )
+    )
+    (drop
+      (i64.or
+        (local.get $y)
+        (i64.const -1)
+      )
+    )
+  )
+  (func $xor (param $x i32) (param $y i64)
+    (drop
+      (i32.xor
+        (local.get $x)
+        (i32.const 0)
+      )
+    )
+  )
+  (func $select-on-const (param $x i32) (param $y i64)
+    (drop
+      (select
+        (i32.const 2)
+        (local.get $x)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (select
+        (i32.const 3)
+        (local.get $x)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select
+        (i32.const 4)
+        (local.tee $x
+          (i32.const 5)
+        )
+        (i32.const 0)
+      )
+    )
+    (drop
+      (select
+        (local.tee $x
+          (i32.const 6)
+        )
+        (i32.const 7)
+        (i32.const 0)
+      )
+    )
+    (drop
+      (select
+        (i32.const 4)
+        (local.tee $x
+          (i32.const 5)
+        )
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select
+        (local.tee $x
+          (i32.const 6)
+        )
+        (i32.const 7)
+        (i32.const 1)
+      )
+    )
+    (drop
+      (select
+        (i32.const 1)
+        (i32.const 0)
+        (local.get $x)
+      )
+    )
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 1)
+        (local.get $x)
+      )
+    )
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 1)
+        (i32.lt_s
+          (local.get $x)
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (i32.const 1)
+        (i32.const 0)
+        (i32.lt_s
+          (local.get $x)
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 1)
+        (i32.ge_s
+          (local.get $x)
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (i32.const 1)
+        (i32.const 0)
+        (i32.gt_s
+          (local.get $x)
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (i32.const 0)
+        (i32.const 1)
+        (i32.gt_s
+          (local.get $x)
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (i32.const 1)
+        (i32.const 0)
+        (i32.ge_s
+          (local.get $x)
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (i64.const 1)
+        (i64.const 0)
+        (local.get $x)
+      )
+    )
+    (drop
+      (select
+        (i64.const 0)
+        (i64.const 1)
+        (local.get $x)
+      )
+    )
+    (drop
+      (select
+        (i64.const 1)
+        (i64.const 0)
+        (i64.eqz
+          (local.get $y)
+        )
+      )
+    )
+    (drop
+      (select
+        (i64.const 0)
+        (i64.const 1)
+        (i64.eqz
+          (local.get $y)
+        )
+      )
+    )
+    (drop
+      (select
+        (i64.const 0)
+        (i64.const 1)
+        (i64.lt_s
+          (local.get $y)
+          (i64.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (i64.const 1)
+        (i64.const 0)
+        (i64.lt_s
+          (local.get $y)
+          (i64.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (i64.const 0)
+        (i64.const 1)
+        (i64.ge_s
+          (local.get $y)
+          (i64.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (i64.const 1)
+        (i64.const 0)
+        (i64.ge_s
+          (local.get $y)
+          (i64.const 0)
+        )
+      )
+    )
+    ;; optimize boolean
+    (drop
+      (select
+        (local.get $x)
+        (i32.const 0)
+        (i32.eqz
+          (i32.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (local.get $x)
+        (i32.const 2)
+        (i32.eqz
+          (i32.const 2)
+        )
+      )
+    )
+    (drop
+      (select
+        (local.get $x)
+        (i32.const 2)
+        (i32.eqz
+          (i32.eqz
+            (local.get $x)
+          )
+        )
+      )
+    )
+    (drop
+      (select
+        (local.get $y)
+        (i64.const 0)
+        (i64.eqz
+          (i64.const 0)
+        )
+      )
+    )
+    (drop
+      (select
+        (local.get $y)
+        (i64.const 2)
+        (i64.eqz
+          (i64.const 2)
+        )
+      )
+    )
+  )
+  (func $optimize-boolean (param $x i32) (param $y i64)
+    ;; bool(-x) -> bool(x)
+    (drop
+      (select
+        (i32.const 1)
+        (i32.const 2)
+        (i32.sub
+          (i32.const 0)
+          (local.get $x)
+        )
+      )
+    )
+    ;; i32(bool(expr)) == 1 -> bool(expr)
+    (drop (i32.eq
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+      (i32.const 1)
+    ))
+    ;; i32(bool(expr)) != 1 -> !bool(expr)
+    (drop (i32.ne
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+      (i32.const 1)
+    ))
+    ;; i64(bool(expr)) != 0 -> i32(bool(expr))
+    (drop (i64.ne
+      (i64.shr_u
+        (local.get $y)
+        (i64.const 63)
+      )
+      (i64.const 0)
+    ))
+    ;; eqz((i32(bool(expr)) != 0) != 0)
+    (drop (i32.eqz
+      (i32.ne
+        (i32.ne
+          (i32.shr_u
+            (local.get $x)
+            (i32.const 31)
+          )
+          (i32.const 0)
+        )
+        (i32.const 0)
+      )
+    ))
+    ;; i32.eqz(wrap(i64(x)))
+    (drop (i32.eqz
+      (i32.wrap_i64
+        (i64.shr_u
+          (local.get $y)
+          (i64.const 63)
+        )
+      )
+    ))
+    ;; eqz((i64(bool(expr)) != 0) != 0)
+    (drop (i32.eqz
+      (i32.ne
+        (i64.ne
+          (i64.shr_u
+            (local.get $y)
+            (i64.const 63)
+          )
+          (i64.const 0)
+        )
+        (i32.const 0)
+      )
+    ))
+    ;; eqz((i64(bool(expr)) != 0) != 0)
+    (drop (i32.eqz
+      (i32.ne
+        (i64.ne
+          (local.get $y)
+          (i64.const 0)
+        )
+        (i32.const 0)
+      )
+    ))
+    ;; i32.eqz(wrap(i64(x))) -> skip
+    (drop (i32.eqz
+      (i32.wrap_i64
+        (local.get $y)
+      )
+    ))
+    ;; i64(bool(expr)) == 1 -> i32(bool(expr))
+    (drop (i64.eq
+      (i64.and
+        (local.get $y)
+        (i64.const 1)
+      )
+      (i64.const 1)
+    ))
+    ;; i64(bool(expr)) != 1 -> !i64(bool(expr))
+    (drop (i64.ne
+      (i64.and
+        (local.get $y)
+        (i64.const 1)
+      )
+      (i64.const 1)
+    ))
+    ;; i32(bool(expr)) & 1 -> bool(expr)
+    (drop (i32.and
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+      (i32.const 1)
+    ))
+    ;; i32(bool(expr)) | 1 -> 1
+    (drop (i32.or
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+      (i32.const 1)
+    ))
+    ;; i64(bool(expr)) & 1 -> i64(bool(expr))
+    (drop (i64.and
+      (i64.and
+        (local.get $y)
+        (i64.const 1)
+      )
+      (i64.const 1)
+    ))
+    ;; i64(bool(expr)) | 1 -> 1
+    (drop (i64.or
+      (i64.and
+        (local.get $y)
+        (i64.const 1)
+      )
+      (i64.const 1)
+    ))
+    ;; i32(bool(expr)) != 0 -> i32(bool(expr))
+    (drop (i32.ne
+      (i32.and
+        (local.get $x)
+        (i32.const 1)
+      )
+      (i32.const 0)
+    ))
+    ;; i32(bool(expr)) != 0 -> i32(bool(expr))
+    (drop (i32.ne
+      (i64.ne
+        (local.get $y)
+        (i64.const 0)
+      )
+      (i32.const 0)
+    ))
+    ;; (i32(expr) != 0) != 0 -> (expr != 0)
+    (drop (i32.ne
+      (i32.ne
+        (local.get $x)
+        (i32.const 0)
+      )
+      (i32.const 0)
+    ))
+    ;; (signed)x % 4 ? 1 : 0
+    (drop (if (result i32)
+      (i32.rem_s
+        (local.get $x)
+        (i32.const 4)
+      )
+      (i32.const 1)
+      (i32.const 0)
+    ))
+    ;; (signed)x % min_s ? 1 : 0
+    (drop (if (result i32)
+      (i32.rem_s
+        (local.get $x)
+        (i32.const 0x80000000)
+      )
+      (i32.const 1)
+      (i32.const 0)
+    ))
+  )
+  (func $optimize-bitwise-oprations (param $x i32) (param $y i32) (param $z i64) (param $w i64)
+    ;; ~(1 << x)  ->  rotl(-2, x)
+    (drop (i32.xor
+      (i32.shl
+        (i32.const 1)
+        (local.get $x)
+      )
+      (i32.const -1)
+    ))
+    (drop (i64.xor
+      (i64.shl
+        (i64.const 1)
+        (local.get $z)
+      )
+      (i64.const -1)
+    ))
+  )
+  (func $getFallthrough ;; unit tests for Properties::getFallthrough
+    (local $x0 i32)
+    (local $x1 i32)
+    (local $x2 i32)
+    (local $x3 i32)
+    (local $x4 i32)
+    (local $x5 i32)
+    (local $x6 i32)
+    (local $x7 i32)
+    ;; the trivial case
+    (local.set $x0 (i32.const 1))
+    (drop (i32.and (local.get $x0) (i32.const 7)))
+    ;; tees
+    (local.set $x1 (local.tee $x2 (i32.const 1)))
+    (drop (i32.and (local.get $x1) (i32.const 7)))
+    ;; loop
+    (local.set $x3 (loop (result i32) (i32.const 1)))
+    (drop (i32.and (local.get $x3) (i32.const 7)))
+    ;; if - two sides, can't
+    (local.set $x4 (if (result i32) (i32.const 1) (i32.const 2) (i32.const 3)))
+    (drop (i32.and (local.get $x4) (i32.const 7)))
+    ;; if - one side, can
+    (local.set $x5 (if (result i32) (i32.const 1) (unreachable) (i32.const 3)))
+    (drop (i32.and (local.get $x5) (i32.const 7)))
+    ;; if - one side, can
+    (local.set $x6 (if (result i32) (i32.const 1) (i32.const 3) (unreachable)))
+    (drop (i32.and (local.get $x6) (i32.const 7)))
+    ;; br_if with value
+    (drop
+      (block $out (result i32)
+        (local.set $x7 (br_if $out (i32.const 1) (i32.const 1)))
+        (drop (i32.and (local.get $x7) (i32.const 7)))
+        (unreachable)
+      )
+    )
+  )
+  (func $tee-with-unreachable-value (result f64)
+   (local $var$0 i32)
+   (block $label$1 (result f64)
+    (local.tee $var$0
+     (br_if $label$1 ;; the f64 does not actually flow through this, it's unreachable (and the type is wrong - but unchecked)
+      (f64.const 1)
+      (unreachable)
+     )
+    )
+   )
+  )
+  (func $add-sub-zero-reorder-1 (param $temp i32) (result i32)
+   (i32.add
+    (i32.add
+     (i32.sub
+      (i32.const 0) ;; this zero looks like we could remove it by subtracting the get of $temp from the parent, but that would reorder it *after* the tee :(
+      (local.get $temp)
+     )
+     (local.tee $temp ;; cannot move this tee before the get
+      (i32.const 1)
+     )
+    )
+    (i32.const 2)
+   )
+  )
+  (func $add-sub-zero-reorder-2 (param $temp i32) (result i32)
+   (i32.add
+    (i32.add
+     (local.tee $temp ;; in this order, the tee already comes first, so all is good for the optimization
+      (i32.const 1)
+     )
+     (i32.sub
+      (i32.const 0)
+      (local.get $temp)
+     )
+    )
+    (i32.const 2)
+   )
+  )
+  (func $const-float-zero (param $fx f32) (param $fy f64)
+    ;; x - 0.0   ==>   x
+    (drop (f32.sub
+      (local.get $fx)
+      (f32.const 0)
+    ))
+    (drop (f64.sub
+      (local.get $fy)
+      (f64.const 0)
+    ))
+    ;; x + (-0.0)   ==>   x
+    (drop (f32.add
+      (local.get $fx)
+      (f32.const -0)
+    ))
+    (drop (f64.add
+      (local.get $fy)
+      (f64.const -0)
+    ))
+    ;; x - (-0.0)   ==>   x + 0.0
+    (drop (f32.sub
+      (local.get $fx)
+      (f32.const -0) ;; skip
+    ))
+    (drop (f64.sub
+      (local.get $fy)
+      (f64.const -0) ;; skip
+    ))
+    ;; 0.0 - x   ==>   0.0 - x
+    (drop (f32.sub
+      (f32.const 0)
+      (local.get $fx) ;; skip
+    ))
+    (drop (f64.sub
+      (f64.const 0)
+      (local.get $fy) ;; skip
+    ))
+    ;; x + 0.0   ==>   x + 0.0
+    (drop (f32.add
+      (local.get $fx) ;; skip
+      (f32.const 0)
+    ))
+    (drop (f64.add
+      (local.get $fy) ;; skip
+      (f64.const 0)
+    ))
+    (drop (f32.sub
+      (f32.const -nan:0x34546d) ;; skip
+      (f32.const 0)
+    ))
+  )
+  (func $rhs-is-neg-one (param $x i32) (param $y i64) (param $fx f32) (param $fy f64)
+    (drop (i32.sub
+      (local.get $x)
+      (i32.const -1)
+    ))
+    (drop (i64.sub
+      (local.get $y)
+      (i64.const -1)
+    ))
+    ;; (unsigned)x > -1   ==>   0
+    (drop (i32.gt_u
+      (local.get $x)
+      (i32.const -1)
+    ))
+    (drop (i64.gt_u
+      (local.get $y)
+      (i64.const -1)
+    ))
+    (drop (i32.gt_s
+      (local.get $x)
+      (i32.const -1)
+    ))
+    (drop (i64.gt_s
+      (local.get $y)
+      (i64.const -1)
+    ))
+    (drop (i64.extend_i32_s
+      (i64.gt_u
+        (i64.const 0)
+        (i64.const -1)
+      )
+    ))
+    ;; (unsigned)x <= -1   ==>   1
+    (drop (i32.le_u
+      (local.get $x)
+      (i32.const -1)
+    ))
+    (drop (i64.le_u
+      (local.get $y)
+      (i64.const -1)
+    ))
+    (drop (i32.le_s
+      (local.get $x)
+      (i32.const -1)
+    ))
+    (drop (i64.le_s
+      (local.get $y)
+      (i64.const -1)
+    ))
+    ;; (unsigned)x >= -1   ==>   x == -1
+    (drop (i32.ge_u
+      (local.get $x)
+      (i32.const -1)
+    ))
+    (drop (i64.ge_u
+      (local.get $y)
+      (i64.const -1)
+    ))
+    ;; (unsigned)x < -1   ==>   x != -1
+    (drop (i32.lt_u
+      (local.get $x)
+      (i32.const -1)
+    ))
+    (drop (i64.lt_u
+      (local.get $y)
+      (i64.const -1)
+    ))
+    ;; x * -1
+    (drop (i32.mul
+      (local.get $x)
+      (i32.const -1)
+    ))
+    (drop (i64.mul
+      (local.get $y)
+      (i64.const -1)
+    ))
+    (drop (f32.mul    ;; skip
+      (local.get $fx)
+      (f32.const -1)
+    ))
+    (drop (f64.mul    ;; skip
+      (local.get $fy)
+      (f64.const -1)
+    ))
+    ;; (unsigned)x / -1
+    (drop (i32.div_u
+      (local.get $x)
+      (i32.const -1)
+    ))
+    (drop (i64.div_u
+      (local.get $y)
+      (i64.const -1)
+    ))
+  )
+  (func $rhs-is-const (param $x i32) (param $y i64) (param $fx f32) (param $fy f64)
+    ;; signed divs
+    ;; i32(x) / -2147483648  ->  x == -2147483648
+    (drop (i32.div_s
+      (local.get $x)
+      (i32.const -2147483648)
+    ))
+    ;; i64(x) / -9223372036854775808  ->  x == -9223372036854775808
+    (drop (i64.div_s
+      (local.get $y)
+      (i64.const -9223372036854775808)
+    ))
+    ;; skip
+    (drop (i64.div_s
+      (local.get $y)
+      (i64.const -2147483648)
+    ))
+
+    ;; unsigned divs
+    ;; u32(x) / -2  =>  x >= -2
+    (drop (i32.div_u
+      (local.get $x)
+      (i32.const -2)
+    ))
+    ;; u32(x) / -1  =>  x == -1
+    (drop (i32.div_u
+      (local.get $x)
+      (i32.const -1)
+    ))
+    ;; u32(x) / (i32.min + 1)
+    (drop (i32.div_u
+      (local.get $x)
+      (i32.const -2147483647)
+    ))
+    ;; u32(x) / i32.min  =>  x >>> 31
+    (drop (i32.div_u
+      (local.get $x)
+      (i32.const -2147483648)
+    ))
+    ;; u64(x) / -1  =>  u64(x == -1)
+    (drop (i64.div_u
+      (local.get $y)
+      (i64.const -1)
+    ))
+    ;; u64(x) / i64.min  =>  x >>> 63
+    (drop (i64.div_u
+      (local.get $y)
+      (i64.const -9223372036854775808)
+    ))
+
+    ;; (unsigned)x >= 0  =>  i32(1)
+    (drop (i32.ge_u
+      (local.get $x)
+      (i32.const 0)
+    ))
+    (drop (i64.ge_u
+      (local.get $y)
+      (i64.const 0)
+    ))
+
+    ;; (unsigned)x < 0  =>  i32(0)
+    (drop (i32.lt_u
+      (local.get $x)
+      (i32.const 0)
+    ))
+    (drop (i64.lt_u
+      (local.get $y)
+      (i64.const 0)
+    ))
+
+    ;; (unsigned)x > 0  =>  x != 0
+    (drop (i32.gt_u
+      (local.get $x)
+      (i32.const 0)
+    ))
+    (drop (i64.gt_u
+      (local.get $y)
+      (i64.const 0)
+    ))
+
+    ;; (unsigned)x <= 0  =>  x == 0
+    (drop (i32.le_u
+      (local.get $x)
+      (i32.const 0)
+    ))
+    (drop (i64.le_u
+      (local.get $y)
+      (i64.const 0)
+    ))
+
+    ;; i32(x) <= 0x7fffffff  =>  i32(1)
+    (drop (i32.le_s
+      (local.get $x)
+      (i32.const 0x7fffffff)
+    ))
+    ;; i64(x) <= 0x7fffffffffffffff  =>  i32(1)
+    (drop (i64.le_s
+      (local.get $y)
+      (i64.const 0x7fffffffffffffff)
+    ))
+
+    ;; i32(x) >= 0x80000000  =>  i32(1)
+    (drop (i32.ge_s
+      (local.get $x)
+      (i32.const 0x80000000)
+    ))
+    ;; i64(x) >= 0x8000000000000000  =>  i32(1)
+    (drop (i64.ge_s
+      (local.get $y)
+      (i64.const 0x8000000000000000)
+    ))
+
+    ;; i32(x) < 0x80000000  =>  0
+    (drop (i32.lt_s
+      (local.get $x)
+      (i32.const 0x80000000)
+    ))
+    ;; i64(x) < 0x8000000000000000  =>  0
+    (drop (i64.lt_s
+      (local.get $y)
+      (i64.const 0x8000000000000000)
+    ))
+
+    ;; i32(x) > 0x7fffffff  =>  0
+    (drop (i32.gt_s
+      (local.get $x)
+      (i32.const 0x7fffffff)
+    ))
+    ;; i64(x) > 0x7fffffffffffffff  =>  0
+    (drop (i64.gt_s
+      (local.get $y)
+      (i64.const 0x7fffffffffffffff)
+    ))
+
+    ;; i32(x) < 0x7fffffff  =>  x != 0x7fffffff
+    (drop (i32.lt_s
+      (local.get $x)
+      (i32.const 0x7fffffff)
+    ))
+    ;; i64(x) < 0x7fffffffffffffff  =>  x != 0x7fffffffffffffff
+    (drop (i64.lt_s
+      (local.get $y)
+      (i64.const 0x7fffffffffffffff)
+    ))
+
+    ;; i32(x) > 0x80000000  =>  x != 0x80000000
+    (drop (i32.gt_s
+      (local.get $x)
+      (i32.const 0x80000000)
+    ))
+    ;; i64(x) > 0x8000000000000000  =>  x != 0x8000000000000000
+    (drop (i64.gt_s
+      (local.get $y)
+      (i64.const 0x8000000000000000)
+    ))
+
+    ;; i32(x) <= 0x80000000  =>  x == 0x80000000
+    (drop (i32.le_s
+      (local.get $x)
+      (i32.const 0x80000000)
+    ))
+    ;; i64(x) <= 0x8000000000000000  =>  x == 0x8000000000000000
+    (drop (i64.le_s
+      (local.get $y)
+      (i64.const 0x8000000000000000)
+    ))
+
+    ;; i32(x) >= 0x7fffffff  =>  x == 0x7fffffff
+    (drop (i32.ge_s
+      (local.get $x)
+      (i32.const 0x7fffffff)
+    ))
+    ;; i64(x) >= 0x7fffffffffffffff  =>  x == 0x7fffffffffffffff
+    (drop (i64.ge_s
+      (local.get $y)
+      (i64.const 0x7fffffffffffffff)
+    ))
+
+    ;; -x * 1  =>  x * -1
+    (drop (f32.mul
+      (f32.neg
+        (local.get $fx)
+      )
+      (f32.const 1)
+    ))
+    ;; -x * -2.1  =>  x * 2.1
+    (drop (f64.mul
+      (f64.neg
+        (local.get $fy)
+      )
+      (f64.const -2.1)
+    ))
+    ;; 2 * -x  =>  x * -2
+    (drop (f64.mul
+      (f64.const 2)
+      (f64.neg
+        (local.get $fy)
+      )
+    ))
+    ;; -x / inf  =>  x / -inf
+    (drop (f32.div
+      (f32.neg
+        (local.get $fx)
+      )
+      (f32.const inf)
+    ))
+    ;; -x / -0.0  =>  x / 0.0
+    (drop (f64.div
+      (f64.neg
+        (local.get $fy)
+      )
+      (f64.const -0.0)
+    ))
+    ;; -x / nan  =>  x / -nan
+    (drop (f64.div
+      (f64.neg
+        (local.get $fy)
+      )
+      (f64.const nan)
+    ))
+    ;; 5.0 / -x  =>  -5 / x
+    (drop (f64.div
+      (f64.const 5)
+      (f64.neg
+        (local.get $fy)
+      )
+    ))
+  )
+  (func $lhs-is-neg-one (param $x i32) (param $y i64)
+    ;; -1 >> x  ==>   -1
+    (drop (i32.shr_s
+      (i32.const -1)
+      (local.get $x)
+    ))
+    (drop (i64.shr_s
+      (i64.const -1)
+      (local.get $y)
+    ))
+    ;; rotl(-1, x)  ==>   -1
+    (drop (i32.rotl
+      (i32.const -1)
+      (local.get $x)
+    ))
+    (drop (i64.rotl
+      (i64.const -1)
+      (local.get $y)
+    ))
+    ;; rotr(-1, x)  ==>   -1
+    (drop (i32.rotr
+      (i32.const -1)
+      (local.get $x)
+    ))
+    (drop (i64.rotr
+      (i64.const -1)
+      (local.get $y)
+    ))
+    ;; skip
+    (drop (i32.shr_s
+      (i32.const -1)
+      (call $ne0) ;; side effect
+    ))
+    ;; skip
+    (drop (i32.shr_u
+      (i32.const -1)
+      (local.get $x)
+    ))
+  )
+  (func $lhs-is-const (param $x i32) (param $y i64)
+    ;; 0 - (x - 1)
+    (drop (i32.sub
+      (i32.const 0)
+      (i32.sub
+        (local.get $x)
+        (i32.const 1)
+      )
+    ))
+    (drop (i64.sub
+      (i64.const 0)
+      (i64.sub
+        (local.get $y)
+        (i64.const 1)
+      )
+    ))
+    ;; -1 - (x + 1)
+    (drop (i32.sub
+      (i32.const -1)
+      (i32.add
+        (local.get $x)
+        (i32.const 1)
+      )
+    ))
+    (drop (i64.sub
+      (i64.const -1)
+      (i64.add
+        (local.get $y)
+        (i64.const 1)
+      )
+    ))
+    ;; 1 - (2 - x)
+    (drop (i32.sub
+      (i32.const 1)
+      (i32.sub
+        (i32.const 2)
+        (local.get $x)
+      )
+    ))
+    (drop (i64.sub
+      (i64.const 1)
+      (i64.sub
+        (i64.const 2)
+        (local.get $y)
+      )
+    ))
+    ;; 0 - (0x80000000 - x)
+    (drop (i32.sub
+      (i32.const 0)
+      (i32.sub
+        (i32.const 0x80000000)
+        (local.get $x)
+      )
+    ))
+  )
+  (func $pre-combine-or (param $x i32) (param $y i32)
+    (drop (i32.or
+      (i32.gt_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.eq
+        (local.get $y) ;; ordering should not stop us
+        (local.get $x)
+      )
+    ))
+    (drop (i32.or
+      (i32.eq ;; ordering should not stop us
+        (local.get $y)
+        (local.get $x)
+      )
+      (i32.gt_s
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    (drop (i32.or
+      (i32.gt_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.eq
+        (local.get $x)
+        (i32.const 1) ;; not equal
+      )
+    ))
+    (drop (i32.or
+      (i32.gt_s
+        (local.get $x)
+        (i32.const 1) ;; not equal
+      )
+      (i32.eq
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    (drop (i32.or
+      (i32.gt_s
+        (call $ne0) ;; side effects
+        (local.get $y)
+      )
+      (i32.eq
+        (call $ne0)
+        (local.get $y)
+      )
+    ))
+    (drop (i32.or
+      (i32.gt_s
+        (local.get $y)
+        (call $ne0) ;; side effects
+      )
+      (i32.eq
+        (local.get $y)
+        (call $ne0)
+      )
+    ))
+  )
+  (func $combine-or (param $x i32) (param $y i32)
+    (drop (i32.or
+      (i32.gt_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.eq
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    ;; TODO: more stuff here
+  )
+  (func $select-into-arms (param $x i32) (param $y i32)
+    (if
+      (select
+        (i32.eqz (i32.eqz (local.get $x)))
+        (i32.eqz (i32.eqz (local.get $y)))
+        (local.get $y)
+      )
+      (unreachable)
+    )
+  )
+  (func $optimize-boolean-context (param $x i32) (param $y i32)
+    ;; 0 - x   ==>   x
+    (if
+      (i32.sub
+        (i32.const 0)
+        (local.get $x)
+      )
+      (unreachable)
+    )
+    (drop (select
+      (local.get $x)
+      (local.get $y)
+      (i32.sub
+        (i32.const 0)
+        (local.get $x)
+      )
+    ))
+  )
+  (func $optimize-relationals (param $x i32) (param $y i32) (param $X i64) (param $Y i64)
+    ;; eqz(x + 0x7FFFFFFF)  ->  x == -2147483647
+    (drop (i32.eqz
+      (i32.add
+        (local.get $x)
+        (i32.const 0x7FFFFFFF)
+      )
+    ))
+    ;; eqz(x + 0x80000000)  ->  x == -2147483648
+    (drop (i32.eqz
+      (i32.add
+        (local.get $x)
+        (i32.const 0x80000000)
+      )
+    ))
+    ;; eqz(x + 0x80000001)  ->  x == 2147483647
+    (drop (i32.eqz
+      (i32.add
+        (local.get $x)
+        (i32.const 0x80000001)
+      )
+    ))
+    ;; eqz(x - y)
+    (drop (i32.eqz
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    (drop (i64.eqz
+      (i64.sub
+        (local.get $X)
+        (local.get $Y)
+      )
+    ))
+    ;; x - y == 0
+    (drop (i32.eq
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    (drop (i64.eq
+      (i64.sub
+        (local.get $X)
+        (local.get $Y)
+      )
+      (i64.const 0)
+    ))
+    ;; x - y != 0
+    (drop (i32.ne
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    (drop (i64.ne
+      (i64.sub
+        (local.get $X)
+        (local.get $Y)
+      )
+      (i64.const 0)
+    ))
+    ;; i32(x - y) > 0  ->  x > y
+    (drop (i32.gt_s
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    ;; i32(x - y) >= 0  ->  x >= y
+    (drop (i32.ge_s
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    ;; u32(x - y) > 0  ->  x != y
+    (drop (i32.gt_u
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    ;; u32(x - y) >= 0  ->  1
+    (drop (i32.ge_u
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    ;; u64(x - y) >= 0  ->  i32(1)
+    (drop (i64.ge_u
+      (i64.sub
+        (local.get $X)
+        (local.get $Y)
+      )
+      (i64.const 0)
+    ))
+    ;; i32(x - y) < 0  ->  x < y
+    (drop (i32.lt_s
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    ;; i32(x - y) <= 0  ->  x <= y
+    (drop (i32.le_s
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    ;; u32(x - y) < 0  ->  0
+    (drop (i32.lt_u
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    ;; u64(x - y) < 0  ->  i32(0)
+    (drop (i64.lt_u
+      (i64.sub
+        (local.get $X)
+        (local.get $Y)
+      )
+      (i64.const 0)
+    ))
+    ;; u32(x - y) <= 0  ->  x == y
+    (drop (i32.le_u
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+      (i32.const 0)
+    ))
+    ;; i32(x - 0x80000000) == 0  ->  x == 0x80000000
+    (drop (i32.eq
+      (i32.sub
+        (local.get $x)
+        (i32.const 0x80000000)
+      )
+      (i32.const 0)
+    ))
+    ;; i32(x - 0x80000000) != 0  ->  x == 0x80000000
+    (drop (i32.ne
+      (i32.sub
+        (local.get $x)
+        (i32.const 0x80000000)
+      )
+      (i32.const 0)
+    ))
+    ;; i32(x - { 0x80000000 }) < 0  ->  skip
+    (drop (i32.lt_s
+      (i32.sub
+        (local.get $x)
+        (i32.const 0x80000000)
+      )
+      (i32.const 0)
+    ))
+    ;; i32(x - { 0x80000000 }) >= 0  ->  skip
+    (drop (i32.ge_s
+      (i32.sub
+        (local.get $x)
+        (i32.const 0x80000000)
+      )
+      (i32.const 0)
+    ))
+    ;; i32(x - { 0x80000000 }) > 0  ->  skip
+    (drop (i32.gt_s
+      (i32.sub
+        (local.get $x)
+        (block (result i32)
+          (i32.const 0x80000000)
+        )
+      )
+      (i32.const 0)
+    ))
+    ;; i32(x - { 0x80000000 }) <= 0  ->  skip
+    (drop (i32.gt_s
+      (i32.sub
+        (local.get $x)
+        (block (result i32)
+          (i32.const 0x80000000)
+        )
+      )
+      (i32.const 0)
+    ))
+  )
+  (func $unsigned-context (param $x i32) (param $y i64)
+    (drop (i32.div_s
+      (i32.and
+        (local.get $x)
+        (i32.const 0x7fffffff)
+      )
+      (i32.const 3)
+    ))
+    (drop (i32.div_s
+      (i32.and
+        (local.get $x)
+        (i32.const 0x7fffffff)
+      )
+      (i32.const -3) ;; skip
+    ))
+    (drop (i32.div_s
+      (i32.and
+        (local.get $x)
+        (i32.const 0x7fffffff)
+      )
+      (i32.const 0x80000000) ;; skip
+    ))
+    (drop (i64.div_s
+      (i64.and
+        (local.get $y)
+        (i64.const 0x7fffffffffffffff)
+      )
+      (i64.const 2)
+    ))
+     (drop (i64.div_s
+      (i64.and
+        (local.get $y)
+        (i64.const 0x7fffffffffffffff)
+      )
+      (i64.const -1) ;; skip
+    ))
+    (drop (i32.rem_s
+      (i32.and
+        (local.get $x)
+        (i32.const 0x7fffffff)
+      )
+      (i32.const 3)
+    ))
+    (drop (i32.shr_s
+      (i32.and
+        (local.get $x)
+        (i32.const 0x7fffffff)
+      )
+      (i32.const 7)
+    ))
+    (drop (i32.ge_s
+      (i32.and
+        (local.get $x)
+        (i32.const 0x7fffffff)
+      )
+      (i32.const 7)
+    ))
+    (drop (i32.ge_s
+      (i32.and
+        (local.get $x)
+        (i32.const 0x7fffffff)
+      )
+      (i32.const -7) ;; skip
+    ))
+  )
+  (func $optimize-float-mul-by-two (param $0 f64) (param $1 f32)
+    (drop (f64.mul
+      (local.get $0)
+      (f64.const 2)
+    ))
+    (drop (f32.mul
+      (local.get $1)
+      (f32.const 2)
+    ))
+
+    (drop (f64.mul
+      (call $tee-with-unreachable-value) ;; side effect
+      (f64.const 2)
+    ))
+    (drop (f64.mul
+      (f64.neg (local.get $0)) ;; complex expression
+      (f64.const 2)
+    ))
+  )
+  (func $duplicate-elimination (param $x i32) (param $y i32) (param $z i32) (param $w f64)
+    ;; unary
+    (drop (f64.abs (f64.abs (local.get $w))))
+    (drop (f64.ceil (f64.ceil (local.get $w))))
+    (drop (f64.floor (f64.floor (local.get $w))))
+    (drop (f64.trunc (f64.trunc (local.get $w))))
+    (drop (f64.nearest (f64.nearest (local.get $w))))
+
+    (drop (f64.nearest (f64.trunc (local.get $w)))) ;; skip
+    (drop (f64.trunc (f64.nearest (local.get $w)))) ;; skip
+
+    (drop (f64.neg (f64.neg (local.get $w))))
+    (drop (f64.neg (f64.neg (f64.neg (local.get $w)))))
+    (drop (f64.neg (f64.neg (f64.neg (f64.neg (local.get $w))))))
+
+    (drop (i32.eqz (i32.eqz (local.get $x)))) ;; skip
+    (drop (i32.eqz (i32.eqz (i32.eqz (local.get $x)))))
+    (drop (i32.eqz (i32.eqz (i64.eqz (i64.const 1)))))
+    (drop (i32.eqz (i32.eqz (i32.ne (local.get $x) (i32.const 2)))))
+
+    (drop (i32.eqz
+      (i32.eqz
+        (i32.and
+          (local.get $x)
+          (i32.const 1)
+        )
+      )
+    ))
+
+    ;; binary
+    ;; ((signed)x % y) % y
+    (drop (i32.rem_s
+      (i32.rem_s
+        (local.get $x)
+        (local.get $y)
+      )
+      (local.get $y)
+    ))
+    ;; ((unsigned)x % y) % y
+    (drop (i32.rem_u
+      (i32.rem_u
+        (local.get $x)
+        (local.get $y)
+      )
+      (local.get $y)
+    ))
+    ;; 0 - (0 - y)
+    (drop (i32.sub
+      (i32.const 0)
+      (i32.sub
+        (i32.const 0)
+        (local.get $y)
+      )
+    ))
+    ;; x - (x - y)
+    (drop (i32.sub
+      (local.get $x)
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    ;; y - (x - y)   -   skip
+    (drop (i32.sub
+      (local.get $y)
+      (i32.sub
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    ;; x ^ (x ^ y)
+    (drop (i32.xor
+      (local.get $x)
+      (i32.xor
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    ;; x ^ (y ^ x)
+    (drop (i32.xor
+      (local.get $x)
+      (i32.xor
+        (local.get $y)
+        (local.get $x)
+      )
+    ))
+    ;; (x ^ y) ^ x
+    (drop (i32.xor
+      (i32.xor
+        (local.get $x)
+        (local.get $y)
+      )
+      (local.get $x)
+    ))
+    ;; (y ^ x) ^ x
+    (drop (i32.xor
+      (i32.xor
+        (local.get $y)
+        (local.get $x)
+      )
+      (local.get $x)
+    ))
+    ;; x ^ (x ^ x)
+    (drop (i32.xor
+      (local.get $x)
+      (i32.xor
+        (local.get $x)
+        (local.get $x)
+      )
+    ))
+    ;; x & (x & y)
+    (drop (i32.and
+      (local.get $x)
+      (i32.and
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    ;; x & (y & x)
+    (drop (i32.and
+      (local.get $x)
+      (i32.and
+        (local.get $y)
+        (local.get $x)
+      )
+    ))
+    ;; (x & y) & x
+    (drop (i32.and
+      (i32.and
+        (local.get $x)
+        (local.get $y)
+      )
+      (local.get $x)
+    ))
+    ;; (y & x) & x
+    (drop (i32.and
+      (i32.and
+        (local.get $y)
+        (local.get $x)
+      )
+      (local.get $x)
+    ))
+    ;; x | (x | y)
+    (drop (i32.or
+      (local.get $x)
+      (i32.or
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    ;; x | (y | x)
+    (drop (i32.or
+      (local.get $x)
+      (i32.or
+        (local.get $y)
+        (local.get $x)
+      )
+    ))
+    ;; (x | y) | x
+    (drop (i32.or
+      (i32.or
+        (local.get $x)
+        (local.get $y)
+      )
+      (local.get $x)
+    ))
+    ;; (y | x) | x
+    (drop (i32.or
+      (i32.or
+        (local.get $y)
+        (local.get $x)
+      )
+      (local.get $x)
+    ))
+    ;; (y | x) | z   -   skip
+    (drop (i32.or
+      (i32.or
+        (local.get $y)
+        (local.get $x)
+      )
+      (local.get $z)
+    ))
+    ;; (z | x) | y   -   skip
+    (drop (i32.or
+      (i32.or
+        (local.get $z)
+        (local.get $x)
+      )
+      (local.get $y)
+    ))
+    ;; (SE() | x) | x
+    (drop (i32.or
+      (i32.or
+        (call $ne0) ;; side effect
+        (local.get $x)
+      )
+      (local.get $x)
+    ))
+    ;; (x | SE()) | SE()   -   skip
+    (drop (i32.or
+      (i32.or
+        (local.get $x)
+        (call $ne0) ;; side effect
+      )
+      (call $ne0) ;; side effect
+    ))
+    ;; x | (SE() | x)
+    (drop (i32.or
+      (local.get $x)
+      (i32.or
+        (local.get $x)
+        (call $ne0) ;; side effect
+      )
+    ))
+    ;; SE() | (x | SE())   -   skip
+    (drop (i32.or
+      (call $ne0) ;; side effect
+      (i32.or
+        (call $ne0) ;; side effect
+        (local.get $x)
+      )
+    ))
+    ;; (y % x) % y   -   skip
+    (drop (i32.rem_s
+      (i32.rem_s
+        (local.get $y)
+        (local.get $x)
+      )
+      (local.get $y)
+    ))
+    ;; y % (x % y)   -   skip
+    (drop (i32.rem_u
+      (local.get $y)
+      (i32.rem_u
+        (local.get $x)
+        (local.get $y)
+      )
+    ))
+    ;; x | (y | x)   where x and y cannot be reordered  -  skip
+    (drop
+      (i32.or
+        (local.get $x)
+        (i32.or
+          (local.tee $x
+            (i32.const 1)
+          )
+          (local.get $x)
+        )
+      )
+    )
+    (drop
+      (i32.or
+        (i32.or
+          (local.get $x)
+          (local.tee $x
+            (i32.const 1)
+          )
+        )
+        (local.get $x)
+      )
+    )
+    ;; x ^ (y ^ x)   where x and y cannot be reordered  -  skip
+    (drop
+      (i32.xor
+        (local.get $x)
+        (i32.xor
+          (local.tee $x
+            (i32.const 1)
+          )
+          (local.get $x)
+        )
+      )
+    )
+    (drop
+      (i32.xor
+        (i32.xor
+          (local.get $x)
+          (local.tee $x
+            (i32.const 1)
+          )
+        )
+        (local.get $x)
+      )
+    )
+  )
+  (func $optimize-shifts (param $x i32) (param $y i32) (param $z i64) (param $w i64)
+    ;; i32
+    (drop (i32.shl
+      (local.get $x)
+      (i32.const 32)
+    ))
+    (drop (i32.shr_s
+      (local.get $x)
+      (i32.const 32)
+    ))
+    (drop (i32.shr_u
+      (local.get $x)
+      (i32.const 64)
+    ))
+    (drop (i32.rotl
+      (local.get $x)
+      (i32.const 64)
+    ))
+    (drop (i32.rotr
+      (local.get $x)
+      (i32.const 64)
+    ))
+    ;; i64
+    (drop (i64.shl
+      (local.get $z)
+      (i64.const 64)
+    ))
+    (drop (i64.shr_s
+      (local.get $z)
+      (i64.const 64)
+    ))
+    (drop (i64.shr_u
+      (local.get $z)
+      (i64.const 128)
+    ))
+    (drop (i64.rotl
+      (local.get $z)
+      (i64.const 128)
+    ))
+    (drop (i64.rotr
+      (local.get $z)
+      (i64.const 128)
+    ))
+
+    ;; i32
+    (drop (i32.shl
+      (local.get $x)
+      (i32.and
+        (local.get $y)
+        (i32.const 31)
+      )
+    ))
+    (drop (i32.shl
+      (local.get $x)
+      (i32.and
+        (local.get $y)
+        (i32.const 63)
+      )
+    ))
+    (drop (i32.shr_s
+      (local.get $x)
+      (i32.and
+        (local.get $y)
+        (i32.const 31)
+      )
+    ))
+    (drop (i32.shr_u
+      (local.get $x)
+      (i32.and
+        (local.get $y)
+        (i32.const 31)
+      )
+    ))
+    ;; i64
+    (drop (i64.shl
+      (local.get $z)
+      (i64.and
+        (local.get $w)
+        (i64.const 63)
+      )
+    ))
+    (drop (i64.shl
+      (local.get $z)
+      (i64.and
+        (local.get $w)
+        (i64.const 127)
+      )
+    ))
+    (drop (i64.shr_s
+      (local.get $z)
+      (i64.and
+        (local.get $w)
+        (i64.const 63)
+      )
+    ))
+    (drop (i64.shr_u
+      (local.get $z)
+      (i64.and
+        (local.get $w)
+        (i64.const 63)
+      )
+    ))
+    ;; i32(x) >> (y & 32)  ->  x
+    (drop (i32.shr_u
+      (local.get $x)
+      (i32.and
+        (local.get $y)
+        (i32.const 32)
+      )
+    ))
+    ;; i64(x) >> (y & 64)  ->  x
+    (drop (i64.shr_u
+      (local.get $z)
+      (i64.and
+        (local.get $w)
+        (i64.const 128)
+      )
+    ))
+
+    ;; skip
+    (drop (i64.shl
+      (local.get $z)
+      (i64.and
+        (local.get $w)
+        (i64.const 32)
+      )
+    ))
+    ;; skip
+    (drop (i64.shr_u
+      (local.get $z)
+      (i64.and
+        (local.get $w)
+        (i64.const 31)
+      )
+    ))
+  )
+  (func $optimize-float-points (param $x0 f64) (param $x1 f64) (param $y0 f32) (param $y1 f32)
+    ;; abs(x) * abs(x)   ==>   x * x
+    (drop (f64.mul
+      (f64.abs (local.get $x0))
+      (f64.abs (local.get $x0))
+    ))
+    (drop (f32.mul
+      (f32.abs (local.get $y0))
+      (f32.abs (local.get $y0))
+    ))
+    (drop (f64.mul
+      (f64.abs (f64.add (local.get $x0) (local.get $x1)))
+      (f64.abs (f64.add (local.get $x0) (local.get $x1)))
+    ))
+
+    ;; abs(x) * abs(y)   ==>   abs(x * y)
+    (drop (f64.mul
+      (f64.abs (local.get $x0))
+      (f64.abs (local.get $x1))
+    ))
+    (drop (f32.mul
+      (f32.abs (local.get $y1))
+      (f32.abs (local.get $y0))
+    ))
+
+    (drop (f64.mul
+      (f64.abs (local.get $x0))
+      (f64.abs (f64.const 0)) ;; skip
+    ))
+    (drop (f32.mul
+      (f32.abs (f32.const 0)) ;; skip
+      (f32.abs (local.get $y0))
+    ))
+    (drop (f64.mul
+      (f64.abs (f64.add (local.get $x0) (local.get $x1)))
+      (f64.abs (f64.add (local.get $x0) (local.get $x0)))
+    ))
+
+
+    ;; abs(-x)   ==>   abs(x)
+    (drop (f64.abs
+      (f64.neg (local.get $x0))
+    ))
+    (drop (f32.abs
+      (f32.neg (local.get $y0))
+    ))
+
+    ;; abs(0 - x)   ==>   skip for non-fast math
+    (drop (f64.abs
+      (f64.sub
+        (f64.const 0)
+        (local.get $x0)
+      )
+    ))
+    (drop (f32.abs
+      (f32.sub
+        (f32.const 0)
+        (local.get $y0)
+      )
+    ))
+
+    ;; abs(x) / abs(x)   ==>   x / x
+    (drop (f64.div
+      (f64.abs (local.get $x0))
+      (f64.abs (local.get $x0))
+    ))
+    (drop (f32.div
+      (f32.abs (local.get $y0))
+      (f32.abs (local.get $y0))
+    ))
+    (drop (f64.div
+      (f64.abs (f64.add (local.get $x0) (local.get $x1)))
+      (f64.abs (f64.add (local.get $x0) (local.get $x1)))
+    ))
+
+    ;; abs(x) / abs(y)   ==>   abs(x / y)
+    (drop (f64.div
+      (f64.abs (local.get $x0))
+      (f64.abs (local.get $x1))
+    ))
+    (drop (f32.div
+      (f32.abs (local.get $y1))
+      (f32.abs (local.get $y0))
+    ))
+
+    ;; abs(x * x)   ==>   x * x
+    (drop (f64.abs
+      (f64.mul
+        (local.get $x0)
+        (local.get $x0)
+      )
+    ))
+    (drop (f32.abs
+      (f32.mul
+        (local.get $y0)
+        (local.get $y0)
+      )
+    ))
+
+    ;; abs(x / x)   ==>   x / x
+    (drop (f64.abs
+      (f64.div
+        (local.get $x0)
+        (local.get $x0)
+      )
+    ))
+    (drop (f32.abs
+      (f32.div
+        (local.get $y0)
+        (local.get $y0)
+      )
+    ))
+
+    (drop (f64.div
+      (f64.abs (local.get $x0))
+      (f64.abs (f64.const 0)) ;; skip
+    ))
+    (drop (f32.div
+      (f32.abs (f32.const 0)) ;; skip
+      (f32.abs (local.get $y0))
+    ))
+    (drop (f64.div
+      (f64.abs (f64.add (local.get $x0) (local.get $x1)))
+      (f64.abs (f64.add (local.get $x0) (local.get $x0)))
+    ))
+  )
+)
+;; atomics
+(module
+  (import "env" "memory" (memory $0 (shared 256 256)))
+  (func $x
+   (drop
+    (i32.shr_s
+     (i32.shl
+      (i32.atomic.load8_u ;; can't be signed
+       (i32.const 100)
+      )
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+   )
+  )
+)
+;; bulk memory
+(module
+  (memory 0)
+  (func $optimize-bulk-memory-copy (param $dst i32) (param $src i32) (param $sz i32)
+    (memory.copy  ;; skip
+      (local.get $dst)
+      (local.get $dst)
+      (local.get $sz)
+    )
+
+    (memory.copy  ;; skip
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 0)
+    )
+
+    (memory.copy
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 1)
+    )
+
+    (memory.copy
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 2)
+    )
+
+    (memory.copy
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 3)
+    )
+
+    (memory.copy
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 4)
+    )
+
+    (memory.copy
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 5)
+    )
+
+    (memory.copy
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 6)
+    )
+
+    (memory.copy
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 7)
+    )
+
+    (memory.copy
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 8)
+    )
+
+    (memory.copy
+      (local.get $dst)
+      (local.get $src)
+      (i32.const 16)
+    )
+
+    (memory.copy  ;; skip
+      (local.get $dst)
+      (local.get $src)
+      (local.get $sz)
+    )
+
+    (memory.copy  ;; skip
+      (i32.const 0)
+      (i32.const 0)
+      (i32.load
+        (i32.const 3) ;; side effect
+      )
+    )
+  )
+)
+;; reference types
+(module
+  ;; These functions test if an `if` with subtyped arms is correctly folded
+  ;; 1. if its `ifTrue` and `ifFalse` arms are identical (can fold)
+  (func $if-arms-subtype-fold (result anyref)
+    (if (result anyref)
+      (i32.const 0)
+      (ref.null extern)
+      (ref.null extern)
+    )
+  )
+  ;; 2. if its `ifTrue` and `ifFalse` arms are not identical (cannot fold)
+  (func $if-arms-subtype-nofold (result anyref)
+    (if (result anyref)
+      (i32.const 0)
+      (ref.null extern)
+      (ref.null func)
+    )
+  )
+)
+;; sign-extensions
+(module
+  (func $duplicate-elimination (param $x i32) (param $y i32) (param $z i32) (param $w f64)
+    (drop (i32.extend8_s (i32.extend8_s (local.get $x))))
+    (drop (i32.extend16_s (i32.extend16_s (local.get $x))))
+  )
+)
+;; exceptions
+(module
+  (func $test
+    (if
+      (try (result i32)
+        (do
+          (i32.eqz
+            (i32.eqz
+              (i32.const 123)
+            )
+          )
+        )
+        (catch
+          (drop
+            (pop exnref)
+          )
+          (i32.eqz
+            (i32.eqz
+              (i32.const 456)
+            )
+          )
+        )
+      )
+      (nop)
+    )
+  )
+)
+;; typed function references
+(module
+  (type $i32-i32 (func (param i32) (result i32)))
+  ;; this function has a reference parameter. we analyze parameters, and should
+  ;; not be confused by a type that has no bit size, in particular. this test
+  ;; just verifies that we do not crash on that.
+  (func $call_from-param (param $f (ref null $i32-i32)) (result i32)
+    (unreachable)
   )
 )
diff --git a/binaryen/test/passes/optimize-instructions_fuzz-exec.txt b/binaryen/test/passes/optimize-instructions_fuzz-exec.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-instructions_fuzz-exec.txt
@@ -0,0 +1,383 @@
+[fuzz-exec] calling test32
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x7fff82]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[fuzz-exec] calling test64
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0xfffffffffff82]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[fuzz-exec] calling just-one-nan
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[fuzz-exec] calling ignore
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+(module
+ (type $none_=>_none (func))
+ (type $f32_=>_none (func (param f32)))
+ (type $f64_=>_none (func (param f64)))
+ (import "fuzzing-support" "log-f32" (func $logf32 (param f32)))
+ (import "fuzzing-support" "log-f64" (func $logf64 (param f64)))
+ (export "test32" (func $0))
+ (export "test64" (func $1))
+ (export "just-one-nan" (func $2))
+ (export "ignore" (func $3))
+ (func $0
+  (call $logf32
+   (f32.add
+    (f32.const -nan:0x7fff82)
+    (f32.neg
+     (f32.const -nan:0x7ff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.sub
+    (f32.const -nan:0x7fff82)
+    (f32.neg
+     (f32.const -nan:0x7ff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.mul
+    (f32.const -nan:0x7fff82)
+    (f32.neg
+     (f32.const -nan:0x7ff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.div
+    (f32.const nan:0x7fff82)
+    (f32.const -nan:0x7ff622)
+   )
+  )
+  (call $logf32
+   (f32.copysign
+    (f32.const -nan:0x7fff82)
+    (f32.neg
+     (f32.const -nan:0x7ff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.min
+    (f32.const -nan:0x7fff82)
+    (f32.neg
+     (f32.const -nan:0x7ff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.max
+    (f32.const -nan:0x7fff82)
+    (f32.neg
+     (f32.const -nan:0x7ff622)
+    )
+   )
+  )
+ )
+ (func $1
+  (call $logf64
+   (f64.add
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.sub
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.mul
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.div
+    (f64.const nan:0xfffffffffff82)
+    (f64.const -nan:0xfffffffffa622)
+   )
+  )
+  (call $logf64
+   (f64.copysign
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.min
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.max
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+ )
+ (func $2
+  (call $logf32
+   (f32.add
+    (f32.neg
+     (f32.const -nan:0x7ff622)
+    )
+    (f32.const 0)
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.const -nan:0x7ff622)
+    (f32.neg
+     (f32.const 0)
+    )
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.neg
+     (f32.const -nan:0x7ff622)
+    )
+    (f32.const -0)
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.const -nan:0x7ff622)
+    (f32.neg
+     (f32.const -0)
+    )
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.neg
+     (f32.const nan:0x7ff622)
+    )
+    (f32.const 0)
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.const nan:0x7ff622)
+    (f32.neg
+     (f32.const 0)
+    )
+   )
+  )
+ )
+ (func $3
+  (call $logf32
+   (f32.div
+    (f32.const -0)
+    (f32.const 0)
+   )
+  )
+  (call $logf32
+   (f32.div
+    (f32.const 0)
+    (f32.const 0)
+   )
+  )
+  (call $logf32
+   (f32.div
+    (f32.const -0)
+    (f32.const -0)
+   )
+  )
+  (call $logf32
+   (f32.div
+    (f32.const 0)
+    (f32.const -0)
+   )
+  )
+ )
+)
+[fuzz-exec] calling test32
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x7fff82]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[fuzz-exec] calling test64
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0xfffffffffff82]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[LoggingExternalInterface logging nan:0x8000000000000]
+[fuzz-exec] calling just-one-nan
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[fuzz-exec] calling ignore
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[LoggingExternalInterface logging nan:0x400000]
+[fuzz-exec] calling foo
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 0]
+[fuzz-exec] calling do-shift
+[LoggingExternalInterface logging -64]
+[fuzz-exec] calling call-compare-maybe-signed-eq
+[fuzz-exec] note result: call-compare-maybe-signed-eq => 0
+[fuzz-exec] calling call-compare-maybe-signed-ne
+[fuzz-exec] note result: call-compare-maybe-signed-ne => 1
+(module
+ (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (import "fuzzing-support" "log-i32" (func $log (param i32)))
+ (export "foo" (func $1))
+ (export "do-shift" (func $3))
+ (export "call-compare-maybe-signed-eq" (func $5))
+ (export "call-compare-maybe-signed-ne" (func $7))
+ (func $signed-comparison-to-unsigned
+  (call $log
+   (block (result i32)
+    (drop
+     (i32.const -25749)
+    )
+    (i32.const 0)
+   )
+  )
+  (call $log
+   (block (result i32)
+    (drop
+     (i32.const -25749)
+    )
+    (i32.const 0)
+   )
+  )
+  (call $log
+   (block (result i32)
+    (drop
+     (i32.const -25749)
+    )
+    (i32.const 1)
+   )
+  )
+ )
+ (func $1 (param $0 i32)
+  (call $log
+   (i32.le_s
+    (i32.sub
+     (i32.const 8)
+     (block $label$1 (result i32)
+      (i32.const -2147483648)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+  (call $log
+   (i32.le_s
+    (i32.const -2147483640)
+    (i32.const 0)
+   )
+  )
+  (call $log
+   (i32.eq
+    (i32.const 8)
+    (i32.const -2147483648)
+   )
+  )
+ )
+ (func $shift (param $0 i32)
+  (call $log
+   (i32.shr_s
+    (i32.shl
+     (i32.shr_s
+      (i32.shl
+       (local.get $0)
+       (i32.const 24)
+      )
+      (i32.const 24)
+     )
+     (i32.const 30)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func $3
+  (call $shift
+   (i32.const 65419)
+  )
+ )
+ (func $compare-maybe-signed-eq (param $0 i32) (result i32)
+  (drop
+   (local.get $0)
+  )
+  (i32.const 0)
+ )
+ (func $5 (result i32)
+  (call $compare-maybe-signed-eq
+   (i32.const 128)
+  )
+ )
+ (func $compare-maybe-signed-ne (param $0 i32) (result i32)
+  (drop
+   (local.get $0)
+  )
+  (i32.const 1)
+ )
+ (func $7 (result i32)
+  (call $compare-maybe-signed-ne
+   (i32.const 128)
+  )
+ )
+)
+[fuzz-exec] calling foo
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 0]
+[fuzz-exec] calling do-shift
+[LoggingExternalInterface logging -64]
+[fuzz-exec] calling call-compare-maybe-signed-eq
+[fuzz-exec] note result: call-compare-maybe-signed-eq => 0
+[fuzz-exec] calling call-compare-maybe-signed-ne
+[fuzz-exec] note result: call-compare-maybe-signed-ne => 1
+[fuzz-exec] comparing call-compare-maybe-signed-eq
+[fuzz-exec] comparing call-compare-maybe-signed-ne
diff --git a/binaryen/test/passes/optimize-instructions_fuzz-exec.wast b/binaryen/test/passes/optimize-instructions_fuzz-exec.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/optimize-instructions_fuzz-exec.wast
@@ -0,0 +1,352 @@
+(module
+ (import "fuzzing-support" "log-f32" (func $logf32 (param f32)))
+ (import "fuzzing-support" "log-f64" (func $logf64 (param f64)))
+ (func "test32"
+  (call $logf32
+   (f32.add
+    (f32.const -nan:0xffff82)
+    (f32.neg
+     (f32.const -nan:0xfff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.sub
+    (f32.const -nan:0xffff82)
+    (f32.neg
+     (f32.const -nan:0xfff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.mul
+    (f32.const -nan:0xffff82)
+    (f32.neg
+     (f32.const -nan:0xfff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.div
+    (f32.const -nan:0xffff82)
+    (f32.neg
+     (f32.const -nan:0xfff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.copysign
+    (f32.const -nan:0xffff82)
+    (f32.neg
+     (f32.const -nan:0xfff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.min
+    (f32.const -nan:0xffff82)
+    (f32.neg
+     (f32.const -nan:0xfff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.max
+    (f32.const -nan:0xffff82)
+    (f32.neg
+     (f32.const -nan:0xfff622)
+    )
+   )
+  )
+ )
+ (func "test64"
+  (call $logf64
+   (f64.add
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.sub
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.mul
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.div
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.copysign
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.min
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+  (call $logf64
+   (f64.max
+    (f64.const -nan:0xfffffffffff82)
+    (f64.neg
+     (f64.const -nan:0xfffffffffa622)
+    )
+   )
+  )
+ )
+ (func "just-one-nan"
+  (call $logf32
+   (f32.add
+    (f32.const 0)
+    (f32.neg
+     (f32.const -nan:0xfff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.const -nan:0xfff622)
+    (f32.neg
+     (f32.const 0)
+    )
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.const -0)
+    (f32.neg
+     (f32.const -nan:0xfff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.const -nan:0xfff622)
+    (f32.neg
+     (f32.const -0)
+    )
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.const 0)
+    (f32.neg
+     (f32.const nan:0xfff622)
+    )
+   )
+  )
+  (call $logf32
+   (f32.add
+    (f32.const nan:0xfff622)
+    (f32.neg
+     (f32.const 0)
+    )
+   )
+  )
+ )
+ (func "ignore"
+  ;; none of these are nan inputs, so the interpreter must not change the sign
+  (call $logf32
+   (f32.div
+    (f32.const 0)
+    (f32.neg
+     (f32.const 0)
+    )
+   )
+  )
+  (call $logf32
+   (f32.div
+    (f32.const -0)
+    (f32.neg
+     (f32.const 0)
+    )
+   )
+  )
+  (call $logf32
+   (f32.div
+    (f32.const 0)
+    (f32.neg
+     (f32.const -0)
+    )
+   )
+  )
+  (call $logf32
+   (f32.div
+    (f32.const -0)
+    (f32.neg
+     (f32.const -0)
+    )
+   )
+  )
+ )
+)
+(module
+ (import "fuzzing-support" "log-i32" (func $log (param i32)))
+ (func $signed-comparison-to-unsigned
+  (call $log
+   (i32.eq               ;; should be false
+    (i32.shr_s           ;; 0x0000006b after the sign-extend
+     (i32.shl
+      (i32.const -25749) ;; 0xffff9b6b
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+    (i32.const -149)     ;; 0xffffff6b - high bits are set, but not sign bit
+   )
+  )
+  ;; the same, with mixed high bits. mixed bits mean the two sides can never be
+  ;; equal, so the eq is always false
+  (call $log
+   (i32.eq
+    (i32.shr_s
+     (i32.shl
+      (i32.const -25749)
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+    (i32.const 0xffffeb)
+   )
+  )
+  ;; the same, with !=, so the result is always true
+  (call $log
+   (i32.ne
+    (i32.shr_s
+     (i32.shl
+      (i32.const -25749)
+      (i32.const 24)
+     )
+     (i32.const 24)
+    )
+    (i32.const 0xffffeb)
+   )
+  )
+ )
+ (func "foo" (param $0 i32)
+  ;; 8 - 0x80000000 < 0
+  ;;
+  ;; is not the same as
+  ;;
+  ;; 8 < 0x80000000
+  ;;
+  ;; because of overflow. the former is true, the latter is false
+  (call $log
+   (i32.le_s
+    (i32.sub
+     (i32.const 8)
+     (block $label$1 (result i32) ;; the block prevents us from optimizing this
+                                  ;; which would avoid the issue. a global or a
+                                  ;; call would do the same, all would make the
+                                  ;; value only visible at runtime
+      (i32.const 0x80000000)
+     )
+    )
+    (i32.const 0)
+   )
+  )
+  ;; for comparison, without the block.
+  (call $log
+   (i32.le_s
+    (i32.sub
+     (i32.const 8)
+     (i32.const 0x80000000)
+    )
+    (i32.const 0)
+   )
+  )
+  ;; for comparison, what X - Y < 0 => X < Y would lead to, which has a
+  ;; different value
+  (call $log
+   (i32.le_s
+    (i32.const 8)
+    (i32.const 0x80000000)
+   )
+  )
+ )
+ (func $shift (param $0 i32)
+  (call $log
+   ;; x << 24 >> 24 << 30 >> 24 - the extra shifts make it invalid to do the
+   ;; optimization of not repeating a sign-extend. That is, this would be valid
+   ;; if the 30 were replaced by a 24.
+   (i32.shr_s
+    (i32.shl
+     (i32.shr_s
+      (i32.shl
+       (local.get $0)
+       (i32.const 24)
+      )
+      (i32.const 24)
+     )
+     (i32.const 30)
+    )
+    (i32.const 24)
+   )
+  )
+ )
+ (func "do-shift"
+  (call $shift
+   (i32.const 65419)
+  )
+ )
+ ;; similar, but with the value compared to having the sign bit set but no
+ ;; upper bits
+ (func $compare-maybe-signed-eq (param $0 i32) (result i32)
+  (i32.eq
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+   (i32.const 128)
+  )
+ )
+ (func "call-compare-maybe-signed-eq" (result i32)
+  (call $compare-maybe-signed-eq
+   (i32.const 128)
+  )
+ )
+ ;; the same with !=
+ (func $compare-maybe-signed-ne (param $0 i32) (result i32)
+  (i32.ne
+   (i32.shr_s
+    (i32.shl
+     (local.get $0)
+     (i32.const 24)
+    )
+    (i32.const 24)
+   )
+   (i32.const 128)
+  )
+ )
+ (func "call-compare-maybe-signed-ne" (result i32)
+  (call $compare-maybe-signed-ne
+   (i32.const 128)
+  )
+ )
+)
diff --git a/binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.txt b/binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.txt
--- a/binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.txt
+++ b/binaryen/test/passes/optimize-instructions_optimize-level=2_all-features_ignore-implicit-traps.txt
@@ -61,14 +61,14 @@
      )
     )
     (br_if $while-in6
-     (i32.lt_s
+     (i32.gt_s
+      (local.get $4)
       (local.tee $3
        (i32.add
         (local.get $3)
         (i32.const 1)
        )
       )
-      (local.get $4)
      )
     )
    )
@@ -144,14 +144,14 @@
      )
     )
     (br_if $while-in6
-     (i32.lt_s
+     (i32.gt_s
+      (local.get $4)
       (local.tee $3
        (i32.add
         (local.get $3)
         (i32.const 1)
        )
       )
-      (local.get $4)
      )
     )
    )
@@ -226,14 +226,14 @@
      )
     )
     (br_if $while-in6
-     (i32.lt_s
+     (i32.gt_s
+      (local.get $4)
       (local.tee $3
        (i32.add
         (local.get $3)
         (i32.const 1)
        )
       )
-      (local.get $4)
      )
     )
    )
@@ -261,9 +261,9 @@
       (i32.and
        (i32.shr_s
         (i32.shl
-         (i32.add
+         (i32.sub
           (local.get $1)
-          (i32.const -1)
+          (i32.const 1)
          )
          (i32.const 24)
         )
@@ -300,9 +300,9 @@
       (i32.and
        (i32.shr_s
         (i32.shl
-         (i32.add
+         (i32.sub
           (local.get $0)
-          (i32.const -1)
+          (i32.const 1)
          )
          (i32.const 24)
         )
diff --git a/binaryen/test/passes/pick-load-signs_all-features.txt b/binaryen/test/passes/pick-load-signs_all-features.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/pick-load-signs_all-features.txt
@@ -0,0 +1,24 @@
+(module
+ (type $none_=>_i32 (func (result i32)))
+ (memory $0 (shared 16 16))
+ (func $atomics-are-always-unsigned (result i32)
+  (local $0 i32)
+  (drop
+   (block $block (result i32)
+    (local.set $0
+     (i32.atomic.load16_u
+      (i32.const 27)
+     )
+    )
+    (i32.shr_s
+     (i32.shl
+      (local.get $0)
+      (i32.const 16)
+     )
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.const -65)
+ )
+)
diff --git a/binaryen/test/passes/pick-load-signs_all-features.wast b/binaryen/test/passes/pick-load-signs_all-features.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/pick-load-signs_all-features.wast
@@ -0,0 +1,23 @@
+(module
+ (memory $0 (shared 16 16))
+ (func $atomics-are-always-unsigned (result i32)
+  (local $0 i32)
+  (drop
+   (block (result i32)
+    (local.set $0
+     (i32.atomic.load16_u ;; an atomic load cannot become signed
+      (i32.const 27)
+     )
+    )
+    (i32.shr_s
+     (i32.shl
+      (local.get $0)
+      (i32.const 16)
+     )
+     (i32.const 16)
+    )
+   )
+  )
+  (i32.const -65)
+ )
+)
diff --git a/binaryen/test/passes/post-emscripten.txt b/binaryen/test/passes/post-emscripten.txt
--- a/binaryen/test/passes/post-emscripten.txt
+++ b/binaryen/test/passes/post-emscripten.txt
@@ -2,83 +2,19 @@
  (type $i32_f32_=>_none (func (param i32 f32)))
  (type $none_=>_none (func))
  (type $i32_i32_f32_=>_none (func (param i32 i32 f32)))
- (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
- (import "global.Math" "pow" (func $Math_pow (param f64 f64) (result f64)))
  (import "env" "invoke_vif" (func $invoke_vif (param i32 i32 f32)))
  (memory $0 256 256)
  (table $0 7 7 funcref)
- (elem (i32.const 0) $pow2 $pow.2 $exc $other_safe $other_unsafe $deep_safe $deep_unsafe)
- (func $pow2
-  (local $x f64)
-  (local $y f64)
-  (local $2 f64)
-  (local $3 f64)
-  (drop
-   (f64.mul
-    (local.tee $2
-     (f64.const 1)
-    )
-    (local.get $2)
-   )
-  )
-  (drop
-   (call $Math_pow
-    (f64.const 1)
-    (f64.const 3)
-   )
-  )
-  (drop
-   (call $Math_pow
-    (f64.const 2)
-    (f64.const 1)
-   )
-  )
-  (local.set $x
-   (f64.const 5)
-  )
-  (drop
-   (f64.mul
-    (local.get $x)
-    (local.get $x)
-   )
-  )
-  (drop
-   (f64.mul
-    (local.tee $y
-     (f64.const 7)
-    )
-    (local.get $y)
-   )
-  )
-  (drop
-   (f64.mul
-    (local.tee $3
-     (f64.const 8)
-    )
-    (local.get $3)
-   )
-  )
- )
- (func $pow.2
-  (drop
-   (f64.sqrt
-    (f64.const 1)
-   )
-  )
-  (drop
-   (call $Math_pow
-    (f64.const 1)
-    (f64.const 0.51)
-   )
-  )
+ (elem (i32.const 0) $f1 $exc $other_safe $other_unsafe $deep_safe $deep_unsafe)
+ (func $f1
+  (nop)
  )
  (func $exc
   (call $other_safe
    (i32.const 42)
    (f32.const 3.141590118408203)
   )
-  (call $invoke_vif
-   (i32.const 4)
+  (call $other_unsafe
    (i32.const 55)
    (f32.const 2.1828181743621826)
   )
@@ -86,8 +22,7 @@
    (i32.const 100)
    (f32.const 1.1109999418258667)
   )
-  (call $invoke_vif
-   (i32.const 6)
+  (call $deep_unsafe
    (i32.const 999)
    (f32.const 1.4140000343322754)
   )
@@ -104,12 +39,7 @@
   (nop)
  )
  (func $other_unsafe (param $0 i32) (param $1 f32)
-  (drop
-   (call $Math_pow
-    (f64.const 1)
-    (f64.const 3)
-   )
-  )
+  (nop)
  )
  (func $deep_safe (param $0 i32) (param $1 f32)
   (call $other_safe
@@ -134,9 +64,7 @@
  (type $none_=>_none (func))
  (type $i32_i32_f32_=>_none (func (param i32 i32 f32)))
  (type $i32_f32_=>_none (func (param i32 f32)))
- (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
  (import "env" "glob" (global $glob i32))
- (import "global.Math" "pow" (func $Math_pow (param f64 f64) (result f64)))
  (import "env" "invoke_vif" (func $invoke_vif (param i32 i32 f32)))
  (memory $0 256 256)
  (table $0 7 7 funcref)
@@ -156,9 +84,7 @@
  (type $none_=>_none (func))
  (type $i32_i32_f32_=>_none (func (param i32 i32 f32)))
  (type $i32_f32_=>_none (func (param i32 f32)))
- (type $f64_f64_=>_f64 (func (param f64 f64) (result f64)))
  (import "env" "glob" (global $glob i32))
- (import "global.Math" "pow" (func $Math_pow (param f64 f64) (result f64)))
  (import "env" "invoke_vif" (func $invoke_vif (param i32 i32 f32)))
  (memory $0 256 256)
  (table $0 7 7 funcref)
diff --git a/binaryen/test/passes/post-emscripten.wast b/binaryen/test/passes/post-emscripten.wast
--- a/binaryen/test/passes/post-emscripten.wast
+++ b/binaryen/test/passes/post-emscripten.wast
@@ -1,83 +1,28 @@
 (module
   (type $0 (func (param i32)))
-  (import "global.Math" "pow" (func $Math_pow (param f64 f64) (result f64)))
   (import "env" "invoke_vif" (func $invoke_vif (param i32 i32 f32)))
   (memory 256 256)
   (table 7 7 funcref)
-  (elem (i32.const 0) $pow2 $pow.2 $exc $other_safe $other_unsafe $deep_safe $deep_unsafe)
-  (func $pow2
-    (local $x f64)
-    (local $y f64)
-    (drop
-      (call $Math_pow
-        (f64.const 1)
-        (f64.const 2)
-      )
-    )
-    (drop
-      (call $Math_pow
-        (f64.const 1)
-        (f64.const 3)
-      )
-    )
-    (drop
-      (call $Math_pow
-        (f64.const 2)
-        (f64.const 1)
-      )
-    )
-    (local.set $x (f64.const 5))
-    (drop
-      (call $Math_pow
-        (local.get $x)
-        (f64.const 2)
-      )
-    )
-    (drop
-      (call $Math_pow
-        (local.tee $y (f64.const 7))
-        (f64.const 2)
-      )
-    )
-    (drop
-      (call $Math_pow
-        (f64.const 8)
-        (f64.const 2)
-      )
-    )
-  )
-  (func $pow.2
-    (drop
-      (call $Math_pow
-        (f64.const 1)
-        (f64.const 0.5)
-      )
-    )
-    (drop
-      (call $Math_pow
-        (f64.const 1)
-        (f64.const 0.51)
-      )
-    )
-  )
+  (elem (i32.const 0) $f1 $exc $other_safe $other_unsafe $deep_safe $deep_unsafe)
+  (func $f1)
   (func $exc
     (call $invoke_vif
-      (i32.const 3) ;; other_safe()
+      (i32.const 2) ;; other_safe()
       (i32.const 42)
       (f32.const 3.14159)
     )
     (call $invoke_vif
-      (i32.const 4) ;; other_unsafe()
+      (i32.const 3) ;; other_unsafe()
       (i32.const 55)
       (f32.const 2.18281828)
     )
     (call $invoke_vif
-      (i32.const 5) ;; deep_safe()
+      (i32.const 4) ;; deep_safe()
       (i32.const 100)
       (f32.const 1.111)
     )
     (call $invoke_vif
-      (i32.const 6) ;; deep_unsafe()
+      (i32.const 5) ;; deep_unsafe()
       (i32.const 999)
       (f32.const 1.414)
     )
@@ -90,12 +35,6 @@
   (func $other_safe (param i32) (param f32)
   )
   (func $other_unsafe (param i32) (param f32)
-    (drop
-      (call $Math_pow
-        (f64.const 1)
-        (f64.const 3)
-      )
-    )
   )
   (func $deep_safe (param i32) (param f32)
     (call $other_safe (unreachable) (unreachable))
@@ -111,7 +50,6 @@
 )
 (module ;; non-constant base for elem
   (type $0 (func (param i32)))
-  (import "global.Math" "pow" (func $Math_pow (param f64 f64) (result f64)))
   (import "env" "invoke_vif" (func $invoke_vif (param i32 i32 f32)))
   (import "env" "glob" (global $glob i32)) ;; non-constant table offset
   (memory 256 256)
@@ -129,7 +67,6 @@
 )
 (module ;; indirect call in the invoke target, which we assume might throw
   (type $none_=>_none (func))
-  (import "global.Math" "pow" (func $Math_pow (param f64 f64) (result f64)))
   (import "env" "invoke_vif" (func $invoke_vif (param i32 i32 f32)))
   (import "env" "glob" (global $glob i32)) ;; non-constant table offset
   (memory 256 256)
diff --git a/binaryen/test/passes/precompute_all-features.txt b/binaryen/test/passes/precompute_all-features.txt
--- a/binaryen/test/passes/precompute_all-features.txt
+++ b/binaryen/test/passes/precompute_all-features.txt
@@ -4,8 +4,8 @@
  (type $none_=>_f64 (func (result f64)))
  (type $none_=>_v128 (func (result v128)))
  (type $i32_=>_none (func (param i32)))
- (type $none_=>_i32_i64 (func (result i32 i64)))
  (type $none_=>_externref (func (result externref)))
+ (type $none_=>_i32_i64 (func (result i32 i64)))
  (memory $0 512 512)
  (data (i32.const 0) "passive")
  (global $global i32 (i32.const 1))
diff --git a/binaryen/test/passes/print-call-graph.txt b/binaryen/test/passes/print-call-graph.txt
--- a/binaryen/test/passes/print-call-graph.txt
+++ b/binaryen/test/passes/print-call-graph.txt
@@ -126,8 +126,6 @@
  (elem (i32.const 0) $b0 $___stdio_close $b1 $___stdout_write $___stdio_seek $___stdio_write $b2 $_cleanup_387 $b3)
  (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
  (import "env" "STACK_MAX" (global $STACK_MAX$asm2wasm$import i32))
- (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR$asm2wasm$import i32))
- (import "env" "tempDoublePtr" (global $tempDoublePtr$asm2wasm$import i32))
  (import "env" "ABORT" (global $ABORT$asm2wasm$import i32))
  (import "global" "NaN" (global $nan$asm2wasm$import f64))
  (import "global" "Infinity" (global $inf$asm2wasm$import f64))
@@ -145,8 +143,6 @@
  (import "env" "___syscall146" (func $___syscall146 (param i32 i32) (result i32)))
  (global $STACKTOP (mut i32) (global.get $STACKTOP$asm2wasm$import))
  (global $STACK_MAX (mut i32) (global.get $STACK_MAX$asm2wasm$import))
- (global $DYNAMICTOP_PTR (mut i32) (global.get $DYNAMICTOP_PTR$asm2wasm$import))
- (global $tempDoublePtr (mut i32) (global.get $tempDoublePtr$asm2wasm$import))
  (global $ABORT (mut i32) (global.get $ABORT$asm2wasm$import))
  (global $__THREW__ (mut i32) (i32.const 0))
  (global $threwValue (mut i32) (i32.const 0))
diff --git a/binaryen/test/passes/print-call-graph.wast b/binaryen/test/passes/print-call-graph.wast
--- a/binaryen/test/passes/print-call-graph.wast
+++ b/binaryen/test/passes/print-call-graph.wast
@@ -7,8 +7,6 @@
   (type $FUNCSIG$vii (func (param i32 i32)))
   (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
   (import "env" "STACK_MAX" (global $STACK_MAX$asm2wasm$import i32))
-  (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR$asm2wasm$import i32))
-  (import "env" "tempDoublePtr" (global $tempDoublePtr$asm2wasm$import i32))
   (import "env" "ABORT" (global $ABORT$asm2wasm$import i32))
   (import "global" "NaN" (global $nan$asm2wasm$import f64))
   (import "global" "Infinity" (global $inf$asm2wasm$import f64))
@@ -30,8 +28,6 @@
   (data (global.get $memoryBase) "\05\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\02\00\00\00\b0\04\00\00\00\04\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\n\ff\ff\ff\ff\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\04")
   (global $STACKTOP (mut i32) (global.get $STACKTOP$asm2wasm$import))
   (global $STACK_MAX (mut i32) (global.get $STACK_MAX$asm2wasm$import))
-  (global $DYNAMICTOP_PTR (mut i32) (global.get $DYNAMICTOP_PTR$asm2wasm$import))
-  (global $tempDoublePtr (mut i32) (global.get $tempDoublePtr$asm2wasm$import))
   (global $ABORT (mut i32) (global.get $ABORT$asm2wasm$import))
   (global $__THREW__ (mut i32) (i32.const 0))
   (global $threwValue (mut i32) (i32.const 0))
diff --git a/binaryen/test/passes/remove-non-js-ops.txt b/binaryen/test/passes/remove-non-js-ops.txt
--- a/binaryen/test/passes/remove-non-js-ops.txt
+++ b/binaryen/test/passes/remove-non-js-ops.txt
@@ -6,10 +6,10 @@
  (type $f64_=>_f64 (func (param f64) (result f64)))
  (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
  (type $i32_=>_none (func (param i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
- (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
  (type $f32_=>_none (func (param f32)))
  (type $f64_=>_none (func (param f64)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
  (type $none_=>_i32 (func (result i32)))
  (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
  (type $i32_i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32 i32) (result i32)))
@@ -103,12 +103,12 @@
   )
  )
  (func $trunc64 (param $0 f64) (result f64)
-  (call $__wasm_trunc_f64
+  (f64.trunc
    (local.get $0)
   )
  )
  (func $trunc32 (param $0 f32) (result f32)
-  (call $__wasm_trunc_f32
+  (f32.trunc
    (local.get $0)
   )
  )
@@ -1108,34 +1108,6 @@
      (local.get $var$0)
     )
     (local.get $var$1)
-   )
-  )
- )
- (func $__wasm_trunc_f32 (param $var$0 f32) (result f32)
-  (select
-   (f32.ceil
-    (local.get $var$0)
-   )
-   (f32.floor
-    (local.get $var$0)
-   )
-   (f32.lt
-    (local.get $var$0)
-    (f32.const 0)
-   )
-  )
- )
- (func $__wasm_trunc_f64 (param $var$0 f64) (result f64)
-  (select
-   (f64.ceil
-    (local.get $var$0)
-   )
-   (f64.floor
-    (local.get $var$0)
-   )
-   (f64.lt
-    (local.get $var$0)
-    (f64.const 0)
    )
   )
  )
diff --git a/binaryen/test/passes/remove-unused-brs_enable-multivalue.txt b/binaryen/test/passes/remove-unused-brs_enable-multivalue.txt
--- a/binaryen/test/passes/remove-unused-brs_enable-multivalue.txt
+++ b/binaryen/test/passes/remove-unused-brs_enable-multivalue.txt
@@ -1,6 +1,6 @@
 (module
- (type $none_=>_none (func))
  (type $i32_=>_none (func (param i32)))
+ (type $none_=>_none (func))
  (type $none_=>_i32 (func (result i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (type $i32_=>_i32 (func (param i32) (result i32)))
@@ -2285,6 +2285,83 @@
    )
   )
  )
+ (func $selectify-even-with-condition-side-effects (param $0 i32)
+  (drop
+   (select
+    (i32.const 1)
+    (i32.const 0)
+    (i32.rem_s
+     (local.get $0)
+     (i32.const 2)
+    )
+   )
+  )
+ )
+ (func $no-selectify-when-arm-side-effects (param $0 i32)
+  (drop
+   (if (result i32)
+    (i32.rem_s
+     (local.get $0)
+     (i32.const 2)
+    )
+    (local.tee $0
+     (i32.const 1)
+    )
+    (i32.const 0)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.rem_s
+     (local.get $0)
+     (i32.const 2)
+    )
+    (i32.const 0)
+    (local.tee $0
+     (i32.const 1)
+    )
+   )
+  )
+ )
+ (func $no-selectify-when-effects-invalidate (param $0 i32)
+  (local $1 i32)
+  (drop
+   (if (result i32)
+    (i32.rem_s
+     (local.tee $0
+      (i32.const 3)
+     )
+     (i32.const 2)
+    )
+    (local.get $0)
+    (i32.const 0)
+   )
+  )
+  (drop
+   (if (result i32)
+    (i32.rem_s
+     (local.tee $0
+      (i32.const 3)
+     )
+     (i32.const 2)
+    )
+    (i32.const 0)
+    (local.get $0)
+   )
+  )
+  (drop
+   (select
+    (i32.const 0)
+    (local.get $1)
+    (i32.rem_s
+     (local.tee $0
+      (i32.const 3)
+     )
+     (i32.const 2)
+    )
+   )
+  )
+ )
  (func $if-one-side (result i32)
   (local $x i32)
   (local.set $x
@@ -2329,9 +2406,8 @@
   (i32.const 0)
  )
  (func $ifs-copies-recursive (param $20 i32) (result i32)
-  (if
-   (i32.const 1)
-   (local.set $20
+  (local.set $20
+   (select
     (select
      (select
       (i32.const 4)
@@ -2341,6 +2417,8 @@
      (local.get $20)
      (i32.const 2)
     )
+    (local.get $20)
+    (i32.const 1)
    )
   )
   (local.get $20)
@@ -2522,6 +2600,17 @@
      (i32.const 6)
     )
    )
+  )
+ )
+ (func $no-selectify-if-condition-unreachable (result i32)
+  (select
+   (if (result i32)
+    (unreachable)
+    (i32.const 3)
+    (i32.const 4)
+   )
+   (i32.const 1)
+   (i32.const 2)
   )
  )
 )
diff --git a/binaryen/test/passes/remove-unused-brs_enable-multivalue.wast b/binaryen/test/passes/remove-unused-brs_enable-multivalue.wast
--- a/binaryen/test/passes/remove-unused-brs_enable-multivalue.wast
+++ b/binaryen/test/passes/remove-unused-brs_enable-multivalue.wast
@@ -1890,6 +1890,62 @@
       )
     )
   )
+  (func $selectify-even-with-condition-side-effects (param $0 i32)
+    (drop (if (result i32)
+      (i32.rem_s
+        (local.get $0)
+        (i32.const 2)
+      )
+      (i32.const 1)
+      (i32.const 0)
+    ))
+  )
+  (func $no-selectify-when-arm-side-effects (param $0 i32)
+    (drop (if (result i32)
+      (i32.rem_s
+        (local.get $0)
+        (i32.const 2)
+      )
+      (local.tee $0 (i32.const 1))
+      (i32.const 0)
+    ))
+    (drop (if (result i32)
+      (i32.rem_s
+        (local.get $0)
+        (i32.const 2)
+      )
+      (i32.const 0)
+      (local.tee $0 (i32.const 1))
+    ))
+  )
+  (func $no-selectify-when-effects-invalidate (param $0 i32)
+    (local $1 i32)
+    (drop (if (result i32)
+      (i32.rem_s
+        (local.tee $0 (i32.const 3))
+        (i32.const 2)
+      )
+      (local.get $0)
+      (i32.const 0)
+    ))
+    (drop (if (result i32)
+      (i32.rem_s
+        (local.tee $0 (i32.const 3))
+        (i32.const 2)
+      )
+      (i32.const 0)
+      (local.get $0)
+    ))
+    ;; but different locals do not invalidate
+    (drop (if (result i32)
+      (i32.rem_s
+        (local.tee $0 (i32.const 3))
+        (i32.const 2)
+      )
+      (i32.const 0)
+      (local.get $1)
+    ))
+  )
   (func $if-one-side (result i32)
    (local $x i32)
    (local.set $x
@@ -2126,6 +2182,17 @@
      (i32.const 6)
     )
    )
+  )
+ )
+ (func $no-selectify-if-condition-unreachable (result i32)
+  (select
+   (if (result i32)
+    (unreachable)
+    (i32.const 3)
+    (i32.const 4)
+   )
+   (i32.const 1)
+   (i32.const 2)
   )
  )
 )
diff --git a/binaryen/test/passes/remove-unused-brs_shrink-level=1.txt b/binaryen/test/passes/remove-unused-brs_shrink-level=1.txt
--- a/binaryen/test/passes/remove-unused-brs_shrink-level=1.txt
+++ b/binaryen/test/passes/remove-unused-brs_shrink-level=1.txt
@@ -24,13 +24,13 @@
    )
   )
   (drop
-   (if (result i32)
-    (i32.const 1)
+   (select
     (i32.rem_s
      (i32.const 11)
      (i32.const 12)
     )
     (i32.const 27)
+    (i32.const 1)
    )
   )
   (drop
diff --git a/binaryen/test/passes/remove-unused-module-elements_all-features.txt b/binaryen/test/passes/remove-unused-module-elements_all-features.txt
--- a/binaryen/test/passes/remove-unused-module-elements_all-features.txt
+++ b/binaryen/test/passes/remove-unused-module-elements_all-features.txt
@@ -157,7 +157,7 @@
   (local $0 i32)
   (local $1 i64)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $0)
     (local.get $0)
     (local.get $1)
@@ -170,7 +170,7 @@
  (memory $0 (shared 23 256))
  (export "user" (func $user))
  (func $user (result i32)
-  (atomic.notify
+  (memory.atomic.notify
    (i32.const 0)
    (i32.const 0)
   )
diff --git a/binaryen/test/passes/remove-unused-module-elements_all-features.wast b/binaryen/test/passes/remove-unused-module-elements_all-features.wast
--- a/binaryen/test/passes/remove-unused-module-elements_all-features.wast
+++ b/binaryen/test/passes/remove-unused-module-elements_all-features.wast
@@ -128,7 +128,7 @@
     (local $0 i32)
     (local $1 i64)
     (drop
-     (i32.atomic.wait
+     (memory.atomic.wait32
       (local.get $0)
       (local.get $0)
       (local.get $1)
@@ -140,7 +140,7 @@
   (memory $0 (shared 23 256))
   (export "user" $user)
   (func $user (result i32)
-    (atomic.notify (i32.const 0) (i32.const 0))
+    (memory.atomic.notify (i32.const 0) (i32.const 0))
   )
 )
 (module ;; more use checks
diff --git a/binaryen/test/passes/remove-unused-names_code-folding_all-features.txt b/binaryen/test/passes/remove-unused-names_code-folding_all-features.txt
--- a/binaryen/test/passes/remove-unused-names_code-folding_all-features.txt
+++ b/binaryen/test/passes/remove-unused-names_code-folding_all-features.txt
@@ -1822,9 +1822,6 @@
   (block $x
    (try
     (do
-     (local.set $exn
-      (pop exnref)
-     )
      (call $foo)
      (call $foo)
      (call $foo)
diff --git a/binaryen/test/passes/remove-unused-names_code-folding_all-features.wast b/binaryen/test/passes/remove-unused-names_code-folding_all-features.wast
--- a/binaryen/test/passes/remove-unused-names_code-folding_all-features.wast
+++ b/binaryen/test/passes/remove-unused-names_code-folding_all-features.wast
@@ -1273,7 +1273,6 @@
       (try
         (do
           ;; Expressions that can throw should NOT be taken out of 'try' scope.
-          (local.set $exn (pop exnref))
           (call $foo)
           (call $foo)
           (call $foo)
diff --git a/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.txt b/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.txt
--- a/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.txt
+++ b/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.txt
@@ -10,8 +10,6 @@
  (type $i32_=>_i64 (func (param i32) (result i64)))
  (import "env" "memory" (memory $0 256))
  (import "env" "table" (table $timport$0 18 18 funcref))
- (import "env" "DYNAMICTOP_PTR" (global $import$0 i32))
- (import "env" "tempDoublePtr" (global $import$1 i32))
  (import "env" "ABORT" (global $import$2 i32))
  (import "env" "STACKTOP" (global $import$3 i32))
  (import "env" "STACK_MAX" (global $import$4 i32))
@@ -42,8 +40,6 @@
  (import "asm2wasm" "i32s-rem" (func $import$27 (param i32 i32) (result i32)))
  (import "asm2wasm" "i32u-rem" (func $import$28 (param i32 i32) (result i32)))
  (import "asm2wasm" "i32u-div" (func $import$29 (param i32 i32) (result i32)))
- (global $global$0 (mut i32) (global.get $import$0))
- (global $global$1 (mut i32) (global.get $import$1))
  (global $global$2 (mut i32) (global.get $import$2))
  (global $global$3 (mut i32) (global.get $import$3))
  (global $global$4 (mut i32) (global.get $import$4))
diff --git a/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.wast b/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.wast
--- a/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.wast
+++ b/binaryen/test/passes/remove-unused-names_remove-unused-brs_vacuum.wast
@@ -15,8 +15,6 @@
   (type $13 (func (param i32 i32 i32 i32 i32)))
   (type $14 (func (param f64 i32) (result f64)))
   (type $15 (func (param i32 i32 i32 i32) (result i32)))
-  (import "env" "DYNAMICTOP_PTR" (global $import$0 i32))
-  (import "env" "tempDoublePtr" (global $import$1 i32))
   (import "env" "ABORT" (global $import$2 i32))
   (import "env" "STACKTOP" (global $import$3 i32))
   (import "env" "STACK_MAX" (global $import$4 i32))
@@ -49,8 +47,6 @@
   (import "env" "table" (table 18 18 funcref))
   (import "env" "memoryBase" (global $import$32 i32))
   (import "env" "tableBase" (global $import$33 i32))
-  (global $global$0 (mut i32) (global.get $import$0))
-  (global $global$1 (mut i32) (global.get $import$1))
   (global $global$2 (mut i32) (global.get $import$2))
   (global $global$3 (mut i32) (global.get $import$3))
   (global $global$4 (mut i32) (global.get $import$4))
diff --git a/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.txt b/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.txt
--- a/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.txt
+++ b/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.txt
@@ -172,7 +172,7 @@
   (local $0 i32)
   (local $1 i64)
   (drop
-   (i32.atomic.wait
+   (memory.atomic.wait32
     (local.get $0)
     (local.get $0)
     (local.get $1)
@@ -185,7 +185,7 @@
  (memory $0 (shared 23 256))
  (export "user" (func $user))
  (func $user (result i32)
-  (atomic.notify
+  (memory.atomic.notify
    (i32.const 0)
    (i32.const 0)
   )
diff --git a/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.wast b/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.wast
--- a/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.wast
+++ b/binaryen/test/passes/remove-unused-nonfunction-module-elements_all-features.wast
@@ -128,7 +128,7 @@
     (local $0 i32)
     (local $1 i64)
     (drop
-     (i32.atomic.wait
+     (memory.atomic.wait32
       (local.get $0)
       (local.get $0)
       (local.get $1)
@@ -140,7 +140,7 @@
   (memory $0 (shared 23 256))
   (export "user" $user)
   (func $user (result i32)
-    (atomic.notify (i32.const 0) (i32.const 0))
+    (memory.atomic.notify (i32.const 0) (i32.const 0))
   )
 )
 (module ;; more use checks
diff --git a/binaryen/test/passes/reverse_dwarf_abbrevs.bin.txt b/binaryen/test/passes/reverse_dwarf_abbrevs.bin.txt
--- a/binaryen/test/passes/reverse_dwarf_abbrevs.bin.txt
+++ b/binaryen/test/passes/reverse_dwarf_abbrevs.bin.txt
@@ -120,14 +120,14 @@
  (type $none_=>_none (func))
  (type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32)))
  (type $i32_i32_i64_i32_=>_i64 (func (param i32 i32 i64 i32) (result i64)))
- (import "env" "memory" (memory $mimport$3 256 256))
+ (import "env" "memory" (memory $mimport$0 256 256))
  (data (i32.const 1024) "hello, world!\00\00\00\18\04")
  (data (i32.const 1048) "\05")
  (data (i32.const 1060) "\01")
  (data (i32.const 1084) "\02\00\00\00\03\00\00\00\c8\04\00\00\00\04")
  (data (i32.const 1108) "\01")
  (data (i32.const 1123) "\n\ff\ff\ff\ff")
- (import "env" "__indirect_function_table" (table $timport$4 4 funcref))
+ (import "env" "__indirect_function_table" (table $timport$0 4 funcref))
  (elem (i32.const 1) $6 $5 $7)
  (import "wasi_snapshot_preview1" "fd_write" (func $fimport$0 (param i32 i32 i32 i32) (result i32)))
  (import "env" "emscripten_memcpy_big" (func $fimport$1 (param i32 i32 i32) (result i32)))
diff --git a/binaryen/test/passes/roundtrip_signed.bin.txt b/binaryen/test/passes/roundtrip_signed.bin.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/roundtrip_signed.bin.txt
@@ -0,0 +1,26 @@
+(module
+ (type $none_=>_none (func))
+ (memory $0 16 17)
+ (global $global$0 (mut i32) (i32.const 10))
+ (export "as-br_table-index" (func $0))
+ (export "as-local.set-value" (func $0))
+ (func $0
+  (if
+   (i32.eqz
+    (global.get $global$0)
+   )
+   (return)
+  )
+  (global.set $global$0
+   (i32.sub
+    (global.get $global$0)
+    (i32.const 1)
+   )
+  )
+  (drop
+   (i32.load
+    (i32.const 0)
+   )
+  )
+ )
+)
diff --git a/binaryen/test/passes/roundtrip_signed.passes b/binaryen/test/passes/roundtrip_signed.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/roundtrip_signed.passes
@@ -0,0 +1,1 @@
+remove-unused-module-elements_roundtrip_vacuum_remove-unused-brs_merge-blocks_vacuum_duplicate-function-elimination
diff --git a/binaryen/test/passes/roundtrip_signed.wasm b/binaryen/test/passes/roundtrip_signed.wasm
new file mode 100644
Binary files /dev/null and b/binaryen/test/passes/roundtrip_signed.wasm differ
diff --git a/binaryen/test/passes/safe-heap_disable-simd.txt b/binaryen/test/passes/safe-heap_disable-simd.txt
--- a/binaryen/test/passes/safe-heap_disable-simd.txt
+++ b/binaryen/test/passes/safe-heap_disable-simd.txt
@@ -1921,1918 +1921,6 @@
  (type $i32_i32_f32_=>_none (func (param i32 i32 f32)))
  (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
  (type $none_=>_none (func))
- (import "env" "DYNAMICTOP_PTR" (global $foo i32))
- (import "env" "segfault" (func $segfault))
- (import "env" "alignfault" (func $alignfault))
- (memory $0 1 1)
- (func $SAFE_HEAP_LOAD_i32_1_1 (param $0 i32) (param $1 i32) (result i32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 1)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i32.load8_s
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i32_1_U_1 (param $0 i32) (param $1 i32) (result i32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 1)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i32.load8_u
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i32_2_1 (param $0 i32) (param $1 i32) (result i32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i32.load16_s align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i32_2_2 (param $0 i32) (param $1 i32) (result i32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i32.load16_s
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i32_2_U_1 (param $0 i32) (param $1 i32) (result i32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i32.load16_u align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i32_2_U_2 (param $0 i32) (param $1 i32) (result i32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i32.load16_u
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i32_4_1 (param $0 i32) (param $1 i32) (result i32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i32.load align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i32_4_2 (param $0 i32) (param $1 i32) (result i32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i32.load align=2
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i32_4_4 (param $0 i32) (param $1 i32) (result i32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (i32.load
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_1_1 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 1)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.load8_s
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_1_U_1 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 1)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.load8_u
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_2_1 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.load16_s align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_2_2 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i64.load16_s
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_2_U_1 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.load16_u align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_2_U_2 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i64.load16_u
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_4_1 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.load32_s align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_4_2 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i64.load32_s align=2
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_4_4 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (i64.load32_s
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_4_U_1 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.load32_u align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_4_U_2 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i64.load32_u align=2
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_4_U_4 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (i64.load32_u
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_8_1 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.load align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_8_2 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i64.load align=2
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_8_4 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (i64.load align=4
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_i64_8_8 (param $0 i32) (param $1 i32) (result i64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 7)
-   )
-   (call $alignfault)
-  )
-  (i64.load
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_f32_4_1 (param $0 i32) (param $1 i32) (result f32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (f32.load align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_f32_4_2 (param $0 i32) (param $1 i32) (result f32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (f32.load align=2
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_f32_4_4 (param $0 i32) (param $1 i32) (result f32)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (f32.load
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_f64_8_1 (param $0 i32) (param $1 i32) (result f64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (f64.load align=1
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_f64_8_2 (param $0 i32) (param $1 i32) (result f64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (f64.load align=2
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_f64_8_4 (param $0 i32) (param $1 i32) (result f64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (f64.load align=4
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_LOAD_f64_8_8 (param $0 i32) (param $1 i32) (result f64)
-  (local $2 i32)
-  (local.set $2
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $2)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $2)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $2)
-    (i32.const 7)
-   )
-   (call $alignfault)
-  )
-  (f64.load
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i32_1_1 (param $0 i32) (param $1 i32) (param $2 i32)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 1)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i32.store8
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i32_2_1 (param $0 i32) (param $1 i32) (param $2 i32)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i32.store16 align=1
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i32_2_2 (param $0 i32) (param $1 i32) (param $2 i32)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i32.store16
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i32_4_1 (param $0 i32) (param $1 i32) (param $2 i32)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i32.store align=1
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i32_4_2 (param $0 i32) (param $1 i32) (param $2 i32)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i32.store align=2
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i32_4_4 (param $0 i32) (param $1 i32) (param $2 i32)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (i32.store
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_1_1 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 1)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.store8
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_2_1 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.store16 align=1
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_2_2 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 2)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i64.store16
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_4_1 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.store32 align=1
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_4_2 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i64.store32 align=2
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_4_4 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (i64.store32
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_8_1 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (i64.store align=1
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_8_2 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (i64.store align=2
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_8_4 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (i64.store align=4
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_i64_8_8 (param $0 i32) (param $1 i32) (param $2 i64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 7)
-   )
-   (call $alignfault)
-  )
-  (i64.store
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_f32_4_1 (param $0 i32) (param $1 i32) (param $2 f32)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (f32.store align=1
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_f32_4_2 (param $0 i32) (param $1 i32) (param $2 f32)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (f32.store align=2
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_f32_4_4 (param $0 i32) (param $1 i32) (param $2 f32)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 4)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (f32.store
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_f64_8_1 (param $0 i32) (param $1 i32) (param $2 f64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (f64.store align=1
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_f64_8_2 (param $0 i32) (param $1 i32) (param $2 f64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 1)
-   )
-   (call $alignfault)
-  )
-  (f64.store align=2
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_f64_8_4 (param $0 i32) (param $1 i32) (param $2 f64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 3)
-   )
-   (call $alignfault)
-  )
-  (f64.store align=4
-   (local.get $3)
-   (local.get $2)
-  )
- )
- (func $SAFE_HEAP_STORE_f64_8_8 (param $0 i32) (param $1 i32) (param $2 f64)
-  (local $3 i32)
-  (local.set $3
-   (i32.add
-    (local.get $0)
-    (local.get $1)
-   )
-  )
-  (if
-   (i32.or
-    (i32.eq
-     (local.get $3)
-     (i32.const 0)
-    )
-    (i32.gt_u
-     (i32.add
-      (local.get $3)
-      (i32.const 8)
-     )
-     (i32.load
-      (global.get $foo)
-     )
-    )
-   )
-   (call $segfault)
-  )
-  (if
-   (i32.and
-    (local.get $3)
-    (i32.const 7)
-   )
-   (call $alignfault)
-  )
-  (f64.store
-   (local.get $3)
-   (local.get $2)
-  )
- )
-)
-(module
- (type $i32_i32_=>_i64 (func (param i32 i32) (result i64)))
- (type $i32_i32_i64_=>_none (func (param i32 i32 i64)))
- (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
- (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
- (type $i32_i32_f64_=>_none (func (param i32 i32 f64)))
- (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
- (type $i32_i32_f32_=>_none (func (param i32 i32 f32)))
- (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
- (type $none_=>_none (func))
  (type $none_=>_i32 (func (result i32)))
  (import "env" "emscripten_get_sbrk_ptr" (func $foo (result i32)))
  (import "env" "segfault" (func $segfault))
diff --git a/binaryen/test/passes/safe-heap_disable-simd.wast b/binaryen/test/passes/safe-heap_disable-simd.wast
--- a/binaryen/test/passes/safe-heap_disable-simd.wast
+++ b/binaryen/test/passes/safe-heap_disable-simd.wast
@@ -3,10 +3,6 @@
 )
 (module
   (memory 1 1)
-  (import "env" "DYNAMICTOP_PTR" (global $foo i32))
-)
-(module
-  (memory 1 1)
   (import "env" "emscripten_get_sbrk_ptr" (func $foo (result i32)))
 )
 (module
diff --git a/binaryen/test/passes/safe-heap_enable-threads_enable-simd.txt b/binaryen/test/passes/safe-heap_enable-threads_enable-simd.txt
--- a/binaryen/test/passes/safe-heap_enable-threads_enable-simd.txt
+++ b/binaryen/test/passes/safe-heap_enable-threads_enable-simd.txt
@@ -5437,9 +5437,10 @@
  (type $none_=>_none (func))
  (type $i32_i32_f32_=>_none (func (param i32 i32 f32)))
  (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
- (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR i32))
+ (type $none_=>_i32 (func (result i32)))
  (import "env" "segfault" (func $segfault))
  (import "env" "alignfault" (func $alignfault))
+ (import "env" "emscripten_get_sbrk_ptr" (func $emscripten_get_sbrk_ptr (result i32)))
  (memory $0 (shared 100 100))
  (func $actions
   (drop
@@ -5474,7 +5475,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5510,7 +5511,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5540,7 +5541,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5570,7 +5571,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5600,7 +5601,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5630,7 +5631,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5673,7 +5674,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5710,7 +5711,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5740,7 +5741,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5777,7 +5778,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5814,7 +5815,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5844,7 +5845,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5881,7 +5882,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5918,7 +5919,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5955,7 +5956,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -5991,7 +5992,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6021,7 +6022,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6051,7 +6052,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6081,7 +6082,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6111,7 +6112,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6154,7 +6155,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6191,7 +6192,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6221,7 +6222,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6258,7 +6259,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6295,7 +6296,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6325,7 +6326,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6362,7 +6363,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6405,7 +6406,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6442,7 +6443,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6472,7 +6473,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6509,7 +6510,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6546,7 +6547,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6583,7 +6584,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6613,7 +6614,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6650,7 +6651,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6687,7 +6688,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6724,7 +6725,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6761,7 +6762,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6791,7 +6792,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6828,7 +6829,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6865,7 +6866,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6895,7 +6896,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6932,7 +6933,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -6969,7 +6970,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7006,7 +7007,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7036,7 +7037,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7073,7 +7074,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7110,7 +7111,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7147,7 +7148,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7184,7 +7185,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7215,7 +7216,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7246,7 +7247,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7277,7 +7278,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7315,7 +7316,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7353,7 +7354,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7384,7 +7385,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7422,7 +7423,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7460,7 +7461,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7498,7 +7499,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7529,7 +7530,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7560,7 +7561,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7591,7 +7592,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7629,7 +7630,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7667,7 +7668,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7698,7 +7699,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7736,7 +7737,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7774,7 +7775,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7812,7 +7813,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7843,7 +7844,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7881,7 +7882,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7919,7 +7920,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7957,7 +7958,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -7995,7 +7996,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8026,7 +8027,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8064,7 +8065,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8102,7 +8103,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8133,7 +8134,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8171,7 +8172,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8209,7 +8210,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8247,7 +8248,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8278,7 +8279,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8316,7 +8317,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8354,7 +8355,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
@@ -8392,7 +8393,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $emscripten_get_sbrk_ptr)
      )
     )
    )
diff --git a/binaryen/test/passes/safe-heap_enable-threads_enable-simd.wast b/binaryen/test/passes/safe-heap_enable-threads_enable-simd.wast
--- a/binaryen/test/passes/safe-heap_enable-threads_enable-simd.wast
+++ b/binaryen/test/passes/safe-heap_enable-threads_enable-simd.wast
@@ -45,7 +45,6 @@
 ;; pre-existing
 (module
  (type $FUNCSIG$v (func))
- (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR i32))
  (import "env" "segfault" (func $segfault))
  (import "env" "alignfault" (func $alignfault))
  (memory $0 (shared 100 100))
diff --git a/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.txt b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.txt
--- a/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.txt
+++ b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.txt
@@ -5623,7 +5623,8 @@
  (type $none_=>_none (func))
  (type $i64_i64_f32_=>_none (func (param i64 i64 f32)))
  (type $i64_i64_=>_f32 (func (param i64 i64) (result f32)))
- (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR i32))
+ (type $none_=>_i64 (func (result i64)))
+ (import "env" "emscripten_get_sbrk_ptr" (func $foo (result i64)))
  (import "env" "segfault" (func $segfault))
  (import "env" "alignfault" (func $alignfault))
  (memory $0 (shared i64 100 100))
@@ -5660,7 +5661,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5696,7 +5697,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5726,7 +5727,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5756,7 +5757,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5786,7 +5787,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5816,7 +5817,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5861,7 +5862,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5900,7 +5901,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5930,7 +5931,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5969,7 +5970,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6008,7 +6009,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6038,7 +6039,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6077,7 +6078,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6116,7 +6117,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6155,7 +6156,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6191,7 +6192,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6221,7 +6222,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6251,7 +6252,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6281,7 +6282,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6311,7 +6312,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6356,7 +6357,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6395,7 +6396,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6425,7 +6426,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6464,7 +6465,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6503,7 +6504,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6533,7 +6534,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6572,7 +6573,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6617,7 +6618,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6656,7 +6657,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6686,7 +6687,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6725,7 +6726,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6764,7 +6765,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6803,7 +6804,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6833,7 +6834,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6872,7 +6873,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6911,7 +6912,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6950,7 +6951,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6989,7 +6990,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7019,7 +7020,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7058,7 +7059,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7097,7 +7098,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7127,7 +7128,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7166,7 +7167,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7205,7 +7206,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7244,7 +7245,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7274,7 +7275,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7313,7 +7314,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7352,7 +7353,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7391,7 +7392,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7430,7 +7431,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7461,7 +7462,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7492,7 +7493,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7523,7 +7524,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7563,7 +7564,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7603,7 +7604,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7634,7 +7635,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7674,7 +7675,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7714,7 +7715,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7754,7 +7755,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7785,7 +7786,7 @@
       (i64.const 1)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7816,7 +7817,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7847,7 +7848,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7887,7 +7888,7 @@
       (i64.const 2)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7927,7 +7928,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7958,7 +7959,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7998,7 +7999,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8038,7 +8039,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8078,7 +8079,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8109,7 +8110,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8149,7 +8150,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8189,7 +8190,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8229,7 +8230,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8269,7 +8270,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8300,7 +8301,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8340,7 +8341,7 @@
       (i64.const 4)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8380,7 +8381,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8411,7 +8412,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8451,7 +8452,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8491,7 +8492,7 @@
       (i64.const 8)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8531,7 +8532,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8562,7 +8563,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8602,7 +8603,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8642,7 +8643,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8682,7 +8683,7 @@
       (i64.const 16)
      )
      (i64.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
diff --git a/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.wast b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.wast
--- a/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.wast
+++ b/binaryen/test/passes/safe-heap_enable-threads_enable-simd64.wast
@@ -45,7 +45,7 @@
 ;; pre-existing
 (module
  (type $FUNCSIG$v (func))
- (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR i32))
+ (import "env" "emscripten_get_sbrk_ptr" (func $foo (result i64)))
  (import "env" "segfault" (func $segfault))
  (import "env" "alignfault" (func $alignfault))
  (memory $0 (shared i64 100 100))
diff --git a/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.txt b/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.txt
--- a/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.txt
+++ b/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.txt
@@ -5437,7 +5437,8 @@
  (type $none_=>_none (func))
  (type $i32_i32_f32_=>_none (func (param i32 i32 f32)))
  (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
- (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR i32))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "emscripten_get_sbrk_ptr" (func $foo (result i32)))
  (import "env" "segfault" (func $segfault))
  (import "env" "alignfault" (func $alignfault))
  (memory $0 (shared 100 100))
@@ -5474,7 +5475,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5510,7 +5511,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5540,7 +5541,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5570,7 +5571,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5600,7 +5601,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5630,7 +5631,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5673,7 +5674,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5710,7 +5711,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5740,7 +5741,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5777,7 +5778,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5814,7 +5815,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5844,7 +5845,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5881,7 +5882,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5918,7 +5919,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5955,7 +5956,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -5991,7 +5992,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6021,7 +6022,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6051,7 +6052,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6081,7 +6082,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6111,7 +6112,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6154,7 +6155,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6191,7 +6192,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6221,7 +6222,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6258,7 +6259,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6295,7 +6296,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6325,7 +6326,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6362,7 +6363,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6405,7 +6406,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6442,7 +6443,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6472,7 +6473,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6509,7 +6510,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6546,7 +6547,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6583,7 +6584,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6613,7 +6614,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6650,7 +6651,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6687,7 +6688,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6724,7 +6725,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6761,7 +6762,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6791,7 +6792,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6828,7 +6829,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6865,7 +6866,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6895,7 +6896,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6932,7 +6933,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -6969,7 +6970,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7006,7 +7007,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7036,7 +7037,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7073,7 +7074,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7110,7 +7111,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7147,7 +7148,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7184,7 +7185,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7215,7 +7216,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7246,7 +7247,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7277,7 +7278,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7315,7 +7316,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7353,7 +7354,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7384,7 +7385,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7422,7 +7423,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7460,7 +7461,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7498,7 +7499,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7529,7 +7530,7 @@
       (i32.const 1)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7560,7 +7561,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7591,7 +7592,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7629,7 +7630,7 @@
       (i32.const 2)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7667,7 +7668,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7698,7 +7699,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7736,7 +7737,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7774,7 +7775,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7812,7 +7813,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7843,7 +7844,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7881,7 +7882,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7919,7 +7920,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7957,7 +7958,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -7995,7 +7996,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8026,7 +8027,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8064,7 +8065,7 @@
       (i32.const 4)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8102,7 +8103,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8133,7 +8134,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8171,7 +8172,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8209,7 +8210,7 @@
       (i32.const 8)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8247,7 +8248,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8278,7 +8279,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8316,7 +8317,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8354,7 +8355,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
@@ -8392,7 +8393,7 @@
       (i32.const 16)
      )
      (i32.load
-      (global.get $DYNAMICTOP_PTR)
+      (call $foo)
      )
     )
    )
diff --git a/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.wast b/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.wast
--- a/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.wast
+++ b/binaryen/test/passes/safe-heap_low-memory-unused_enable-threads_enable-simd.wast
@@ -45,7 +45,7 @@
 ;; pre-existing
 (module
  (type $FUNCSIG$v (func))
- (import "env" "DYNAMICTOP_PTR" (global $DYNAMICTOP_PTR i32))
+ (import "env" "emscripten_get_sbrk_ptr" (func $foo (result i32)))
  (import "env" "segfault" (func $segfault))
  (import "env" "alignfault" (func $alignfault))
  (memory $0 (shared 100 100))
diff --git a/binaryen/test/passes/safe-heap_start-function.passes b/binaryen/test/passes/safe-heap_start-function.passes
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_start-function.passes
@@ -0,0 +1,1 @@
+safe-heap
diff --git a/binaryen/test/passes/safe-heap_start-function.txt b/binaryen/test/passes/safe-heap_start-function.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_start-function.txt
@@ -0,0 +1,1932 @@
+(module
+ (type $i32_i32_=>_i64 (func (param i32 i32) (result i64)))
+ (type $i32_i32_i64_=>_none (func (param i32 i32 i64)))
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (type $i32_i32_i32_=>_none (func (param i32 i32 i32)))
+ (type $none_=>_none (func))
+ (type $i32_i32_f64_=>_none (func (param i32 i32 f64)))
+ (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
+ (type $i32_i32_f32_=>_none (func (param i32 i32 f32)))
+ (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "emscripten_get_sbrk_ptr" (func $emscripten_get_sbrk_ptr (result i32)))
+ (import "env" "segfault" (func $segfault))
+ (import "env" "alignfault" (func $alignfault))
+ (memory $0 1 1)
+ (start $foo)
+ (func $foo
+  (i32.store
+   (i32.load
+    (i32.const 1234)
+   )
+   (i32.const 5678)
+  )
+ )
+ (func $bar
+  (call $SAFE_HEAP_STORE_i32_4_4
+   (call $SAFE_HEAP_LOAD_i32_4_4
+    (i32.const 1234)
+    (i32.const 0)
+   )
+   (i32.const 0)
+   (i32.const 5678)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_1 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_1_U_1 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_1 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_2 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load16_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_1 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_2_U_2 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_1 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_2 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i32_4_4 (param $0 i32) (param $1 i32) (result i32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_1 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_1_U_1 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load8_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_1 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_2 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load16_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_1 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load16_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_2_U_2 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load16_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_1 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load32_s align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_2 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_s align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_4 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_s
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_1 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load32_u align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_2 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_u align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_4_U_4 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load32_u
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_1 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_2 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_4 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_i64_8_8 (param $0 i32) (param $1 i32) (result i64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_1 (param $0 i32) (param $1 i32) (result f32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f32.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_2 (param $0 i32) (param $1 i32) (result f32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f32.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f32_4_4 (param $0 i32) (param $1 i32) (result f32)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f32.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_1 (param $0 i32) (param $1 i32) (result f64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f64.load align=1
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_2 (param $0 i32) (param $1 i32) (result f64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f64.load align=2
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_4 (param $0 i32) (param $1 i32) (result f64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f64.load align=4
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_LOAD_f64_8_8 (param $0 i32) (param $1 i32) (result f64)
+  (local $2 i32)
+  (local.set $2
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $2)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $2)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $2)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.load
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_1_1 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.store8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_2_1 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_2_2 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.store16
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_4_1 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i32.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_4_2 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i32.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i32_4_4 (param $0 i32) (param $1 i32) (param $2 i32)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i32.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_1_1 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 1)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store8
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_2_1 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store16 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_2_2 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 2)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.store16
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_4_1 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store32 align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_4_2 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.store32 align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_4_4 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.store32
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_8_1 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (i64.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_8_2 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (i64.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_8_4 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (i64.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_i64_8_8 (param $0 i32) (param $1 i32) (param $2 i64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (i64.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_f32_4_1 (param $0 i32) (param $1 i32) (param $2 f32)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f32.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_f32_4_2 (param $0 i32) (param $1 i32) (param $2 f32)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f32.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_f32_4_4 (param $0 i32) (param $1 i32) (param $2 f32)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 4)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f32.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_f64_8_1 (param $0 i32) (param $1 i32) (param $2 f64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (f64.store align=1
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_f64_8_2 (param $0 i32) (param $1 i32) (param $2 f64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 1)
+   )
+   (call $alignfault)
+  )
+  (f64.store align=2
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_f64_8_4 (param $0 i32) (param $1 i32) (param $2 f64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 3)
+   )
+   (call $alignfault)
+  )
+  (f64.store align=4
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+ (func $SAFE_HEAP_STORE_f64_8_8 (param $0 i32) (param $1 i32) (param $2 f64)
+  (local $3 i32)
+  (local.set $3
+   (i32.add
+    (local.get $0)
+    (local.get $1)
+   )
+  )
+  (if
+   (i32.or
+    (i32.eq
+     (local.get $3)
+     (i32.const 0)
+    )
+    (i32.gt_u
+     (i32.add
+      (local.get $3)
+      (i32.const 8)
+     )
+     (i32.load
+      (call $emscripten_get_sbrk_ptr)
+     )
+    )
+   )
+   (call $segfault)
+  )
+  (if
+   (i32.and
+    (local.get $3)
+    (i32.const 7)
+   )
+   (call $alignfault)
+  )
+  (f64.store
+   (local.get $3)
+   (local.get $2)
+  )
+ )
+)
diff --git a/binaryen/test/passes/safe-heap_start-function.wast b/binaryen/test/passes/safe-heap_start-function.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/safe-heap_start-function.wast
@@ -0,0 +1,11 @@
+(module
+  (memory 1 1)
+  (func $foo
+   ;; should not be modified because its the start function
+   (i32.store (i32.load (i32.const 1234)) (i32.const 5678))
+  )
+  (func $bar
+   (i32.store (i32.load (i32.const 1234)) (i32.const 5678))
+  )
+  (start $foo)
+)
diff --git a/binaryen/test/passes/simplify-globals_all-features_fuzz-exec.txt b/binaryen/test/passes/simplify-globals_all-features_fuzz-exec.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-globals_all-features_fuzz-exec.txt
@@ -0,0 +1,20 @@
+[fuzz-exec] calling export
+[fuzz-exec] note result: export => funcref(0)
+(module
+ (type $f32_ref?|i31|_i64_f64_funcref_=>_none (func (param f32 (ref null i31) i64 f64 funcref)))
+ (type $none_=>_funcref (func (result funcref)))
+ (global $global$0 (mut funcref) (ref.null func))
+ (export "export" (func $1))
+ (func $0 (param $0 f32) (param $1 (ref null i31)) (param $2 i64) (param $3 f64) (param $4 funcref)
+  (nop)
+ )
+ (func $1 (result funcref)
+  (global.set $global$0
+   (ref.func $0)
+  )
+  (ref.func $0)
+ )
+)
+[fuzz-exec] calling export
+[fuzz-exec] note result: export => funcref(0)
+[fuzz-exec] comparing export
diff --git a/binaryen/test/passes/simplify-globals_all-features_fuzz-exec.wast b/binaryen/test/passes/simplify-globals_all-features_fuzz-exec.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/simplify-globals_all-features_fuzz-exec.wast
@@ -0,0 +1,14 @@
+(module
+ (global $global$0 (mut funcref) (ref.null func))
+ (func $0 (param $0 f32) (param $1 i31ref) (param $2 i64) (param $3 f64) (param $4 funcref)
+  (nop)
+ )
+ (func "export" (result funcref)
+  ;; this set's value will be applied to the get right after it. we should carry
+  ;; over the specific typed function reference type properly while doing so.
+  (global.set $global$0
+   (ref.func $0)
+  )
+  (global.get $global$0)
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals_all-features.txt b/binaryen/test/passes/simplify-locals_all-features.txt
--- a/binaryen/test/passes/simplify-locals_all-features.txt
+++ b/binaryen/test/passes/simplify-locals_all-features.txt
@@ -6,9 +6,9 @@
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
  (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
  (type $i32_=>_none (func (param i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
  (type $i64_=>_none (func (param i64)))
  (type $f32_=>_none (func (param f32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32)))
  (type $i32_f64_f64_f32_i32_=>_f64 (func (param i32 f64 f64 f32 i32) (result f64)))
@@ -1127,8 +1127,8 @@
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32)))
  (type $i32_=>_none (func (param i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
  (type $f32_=>_none (func (param f32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (type $none_=>_f64 (func (result f64)))
  (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
@@ -1896,8 +1896,8 @@
 )
 (module
  (type $none_=>_none (func))
- (type $i32_exnref_=>_none (func (param i32 exnref)))
  (type $exnref_=>_none (func (param exnref)))
+ (type $i32_exnref_=>_none (func (param i32 exnref)))
  (type $none_=>_i32 (func (result i32)))
  (type $none_=>_exnref (func (result exnref)))
  (event $event$0 (attr 0) (param))
@@ -2037,6 +2037,24 @@
    )
    (data.drop 0)
    (local.get $0)
+  )
+ )
+)
+(module
+ (type $eqref_ref?|i31|_=>_i32 (func (param eqref (ref null i31)) (result i32)))
+ (export "test" (func $0))
+ (func $0 (param $0 eqref) (param $1 (ref null i31)) (result i32)
+  (local $2 eqref)
+  (local $3 (ref null i31))
+  (local.set $2
+   (local.get $0)
+  )
+  (local.set $0
+   (local.get $3)
+  )
+  (ref.eq
+   (local.get $2)
+   (local.get $1)
   )
  )
 )
diff --git a/binaryen/test/passes/simplify-locals_all-features.wast b/binaryen/test/passes/simplify-locals_all-features.wast
--- a/binaryen/test/passes/simplify-locals_all-features.wast
+++ b/binaryen/test/passes/simplify-locals_all-features.wast
@@ -1800,3 +1800,23 @@
   )
  )
 )
+;; do not be confused by subtyping: when an index is set, even to another type,
+;; it is no longer equivalent
+;; (see https://github.com/WebAssembly/binaryen/issues/3266)
+(module
+ (func "test" (param $0 eqref) (param $1 i31ref) (result i32)
+  (local $2 eqref)
+  (local $3 i31ref)
+  (local.set $2
+   (local.get $0) ;; $0 and $2 are equivalent
+  )
+  (local.set $0   ;; set $0 to something with another type
+   (local.get $3)
+  )
+  ;; compares a null eqref and a zero i31ref - should be false
+  (ref.eq
+   (local.get $2)
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.txt b/binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.txt
--- a/binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.txt
+++ b/binaryen/test/passes/simplify-locals_all-features_disable-exception-handling.txt
@@ -6,9 +6,9 @@
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
  (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32)))
  (type $i32_=>_none (func (param i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
  (type $i64_=>_none (func (param i64)))
  (type $f32_=>_none (func (param f32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32)))
  (type $i32_f64_f64_f32_i32_=>_f64 (func (param i32 f64 f64 f32 i32) (result f64)))
@@ -1121,8 +1121,8 @@
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32)))
  (type $i32_=>_none (func (param i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
  (type $f32_=>_none (func (param f32)))
+ (type $i32_i32_=>_none (func (param i32 i32)))
  (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
  (type $none_=>_f64 (func (result f64)))
  (type $i32_i32_=>_f64 (func (param i32 i32) (result f64)))
diff --git a/binaryen/test/passes/spill-pointers.txt b/binaryen/test/passes/spill-pointers.txt
deleted file mode 100644
--- a/binaryen/test/passes/spill-pointers.txt
+++ /dev/null
@@ -1,1291 +0,0 @@
-(module
- (type $none_=>_none (func))
- (type $i32_=>_i32 (func (param i32) (result i32)))
- (type $none_=>_i32 (func (result i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
- (type $i32_=>_none (func (param i32)))
- (type $f64_=>_none (func (param f64)))
- (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
- (import "env" "segfault" (func $segfault (param i32)))
- (memory $0 10)
- (table $0 1 1 funcref)
- (global $stack_ptr (mut i32) (global.get $STACKTOP$asm2wasm$import))
- (func $nothing
-  (nop)
- )
- (func $not-alive
-  (local $x i32)
-  (local.set $x
-   (i32.const 1)
-  )
-  (call $nothing)
- )
- (func $spill
-  (local $x i32)
-  (local $1 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (i32.store
-     (local.get $1)
-     (local.get $x)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
- )
- (func $ignore-non-pointers
-  (local $x i32)
-  (local $y i64)
-  (local $z f32)
-  (local $w f64)
-  (local $4 i32)
-  (local.set $4
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $4)
-    (i32.const 16)
-   )
-  )
-  (block
-   (local.set $x
-    (i32.const 1)
-   )
-   (local.set $y
-    (i64.const 1)
-   )
-   (local.set $z
-    (f32.const 1)
-   )
-   (local.set $w
-    (f64.const 1)
-   )
-   (block
-    (i32.store
-     (local.get $4)
-     (local.get $x)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-   (drop
-    (local.get $y)
-   )
-   (drop
-    (local.get $z)
-   )
-   (drop
-    (local.get $w)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $4)
-  )
- )
- (func $spill4
-  (local $x i32)
-  (local $y i32)
-  (local $z i32)
-  (local $w i32)
-  (local $4 i32)
-  (local.set $4
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $4)
-    (i32.const 16)
-   )
-  )
-  (block
-   (local.set $x
-    (i32.const 1)
-   )
-   (local.set $y
-    (i32.const 1)
-   )
-   (local.set $z
-    (i32.const 1)
-   )
-   (local.set $w
-    (i32.const 1)
-   )
-   (block
-    (i32.store
-     (local.get $4)
-     (local.get $x)
-    )
-    (i32.store offset=4
-     (local.get $4)
-     (local.get $y)
-    )
-    (i32.store offset=8
-     (local.get $4)
-     (local.get $z)
-    )
-    (i32.store offset=12
-     (local.get $4)
-     (local.get $w)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-   (drop
-    (local.get $y)
-   )
-   (drop
-    (local.get $z)
-   )
-   (drop
-    (local.get $w)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $4)
-  )
- )
- (func $spill5
-  (local $x i32)
-  (local $y i32)
-  (local $z i32)
-  (local $w i32)
-  (local $a i32)
-  (local $5 i32)
-  (local.set $5
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $5)
-    (i32.const 32)
-   )
-  )
-  (block
-   (local.set $x
-    (i32.const 1)
-   )
-   (local.set $y
-    (i32.const 1)
-   )
-   (local.set $z
-    (i32.const 1)
-   )
-   (local.set $w
-    (i32.const 1)
-   )
-   (local.set $a
-    (i32.const 1)
-   )
-   (block
-    (i32.store
-     (local.get $5)
-     (local.get $x)
-    )
-    (i32.store offset=4
-     (local.get $5)
-     (local.get $y)
-    )
-    (i32.store offset=8
-     (local.get $5)
-     (local.get $z)
-    )
-    (i32.store offset=12
-     (local.get $5)
-     (local.get $w)
-    )
-    (i32.store offset=16
-     (local.get $5)
-     (local.get $a)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-   (drop
-    (local.get $y)
-   )
-   (drop
-    (local.get $z)
-   )
-   (drop
-    (local.get $w)
-   )
-   (drop
-    (local.get $a)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $5)
-  )
- )
- (func $some-alive
-  (local $x i32)
-  (local $y i32)
-  (local $2 i32)
-  (local.set $2
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $2)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (i32.store
-     (local.get $2)
-     (local.get $x)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $2)
-  )
- )
- (func $spill-args (param $p i32) (param $q i32)
-  (local $x i32)
-  (local $3 i32)
-  (local $4 i32)
-  (local $5 i32)
-  (local.set $3
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $3)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (local.set $4
-     (i32.const 1)
-    )
-    (local.set $5
-     (i32.const 2)
-    )
-    (i32.store offset=8
-     (local.get $3)
-     (local.get $x)
-    )
-    (call $spill-args
-     (local.get $4)
-     (local.get $5)
-    )
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $3)
-  )
- )
- (func $spill-ret (result i32)
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local $3 i32)
-  (local $4 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (local.set $4
-   (block (result i32)
-    (block
-     (i32.store
-      (local.get $1)
-      (local.get $x)
-     )
-     (call $nothing)
-    )
-    (drop
-     (local.get $x)
-    )
-    (if
-     (i32.const 1)
-     (block
-      (local.set $2
-       (i32.const 2)
-      )
-      (global.set $stack_ptr
-       (local.get $1)
-      )
-      (return
-       (local.get $2)
-      )
-     )
-     (block
-      (local.set $3
-       (i32.const 3)
-      )
-      (global.set $stack_ptr
-       (local.get $1)
-      )
-      (return
-       (local.get $3)
-      )
-     )
-    )
-    (i32.const 4)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
-  (local.get $4)
- )
- (func $spill-unreachable (result i32)
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (local.set $2
-   (block (result i32)
-    (block
-     (i32.store
-      (local.get $1)
-      (local.get $x)
-     )
-     (call $nothing)
-    )
-    (drop
-     (local.get $x)
-    )
-    (unreachable)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
-  (local.get $2)
- )
- (func $spill-call-call0 (param $p i32) (result i32)
-  (unreachable)
- )
- (func $spill-call-call1 (param $p i32) (result i32)
-  (local $x i32)
-  (local $2 i32)
-  (local $3 i32)
-  (local $4 i32)
-  (local $5 i32)
-  (local.set $2
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $2)
-    (i32.const 16)
-   )
-  )
-  (local.set $5
-   (block (result i32)
-    (drop
-     (block (result i32)
-      (local.set $3
-       (block (result i32)
-        (local.set $4
-         (i32.const 1)
-        )
-        (i32.store offset=4
-         (local.get $2)
-         (local.get $x)
-        )
-        (call $spill-call-call1
-         (local.get $4)
-        )
-       )
-      )
-      (i32.store offset=4
-       (local.get $2)
-       (local.get $x)
-      )
-      (call $spill-call-call0
-       (local.get $3)
-      )
-     )
-    )
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $2)
-  )
-  (local.get $5)
- )
- (func $spill-call-ret (param $p i32) (result i32)
-  (local $x i32)
-  (drop
-   (call $spill-call-call0
-    (return
-     (i32.const 1)
-    )
-   )
-  )
-  (i32.const 0)
- )
- (func $spill-ret-call (param $p i32) (result i32)
-  (local $x i32)
-  (drop
-   (return
-    (call $spill-call-call0
-     (i32.const 1)
-    )
-   )
-  )
-  (i32.const 0)
- )
- (func $spill-ret-ret (result i32)
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local $3 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (local.set $3
-   (block (result i32)
-    (block
-     (i32.store
-      (local.get $1)
-      (local.get $x)
-     )
-     (call $nothing)
-    )
-    (drop
-     (local.get $x)
-    )
-    (drop
-     (block
-      (global.set $stack_ptr
-       (local.get $1)
-      )
-      (return
-       (block
-        (local.set $2
-         (i32.const 1)
-        )
-        (global.set $stack_ptr
-         (local.get $1)
-        )
-        (return
-         (local.get $2)
-        )
-       )
-      )
-     )
-    )
-    (i32.const 0)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
-  (local.get $3)
- )
- (func $spill-call-othertype (param $y f64)
-  (local $x i32)
-  (local $2 i32)
-  (local $3 f64)
-  (local.set $2
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $2)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (local.set $3
-     (f64.const 1)
-    )
-    (i32.store
-     (local.get $2)
-     (local.get $x)
-    )
-    (call $spill-call-othertype
-     (local.get $3)
-    )
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $2)
-  )
- )
- (func $spill-call_indirect
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local $3 i32)
-  (local $4 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (local.set $2
-     (i32.const 123)
-    )
-    (local.set $3
-     (i32.const 456)
-    )
-    (local.set $4
-     (i32.const 789)
-    )
-    (i32.store
-     (local.get $1)
-     (local.get $x)
-    )
-    (call_indirect (type $i32_i32_=>_none)
-     (local.get $2)
-     (local.get $3)
-     (local.get $4)
-    )
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
- )
- (func $spill-call_import
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (local.set $2
-     (i32.const 200)
-    )
-    (i32.store
-     (local.get $1)
-     (local.get $x)
-    )
-    (call $segfault
-     (local.get $2)
-    )
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
- )
-)
-(module
- (type $none_=>_none (func))
- (type $none_=>_i32 (func (result i32)))
- (type $i32_=>_i32 (func (param i32) (result i32)))
- (type $i32_i32_=>_none (func (param i32 i32)))
- (type $i32_=>_none (func (param i32)))
- (type $f64_=>_none (func (param f64)))
- (import "env" "segfault" (func $segfault (param i32)))
- (memory $0 10)
- (table $0 1 1 funcref)
- (global $stack_ptr (mut i32) (i32.const 1716592))
- (export "stackSave" (func $stack_save))
- (func $stack_save (result i32)
-  (global.get $stack_ptr)
- )
- (func $nothing
-  (nop)
- )
- (func $not-alive
-  (local $x i32)
-  (local.set $x
-   (i32.const 1)
-  )
-  (call $nothing)
- )
- (func $spill
-  (local $x i32)
-  (local $1 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (i32.store
-     (local.get $1)
-     (local.get $x)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
- )
- (func $ignore-non-pointers
-  (local $x i32)
-  (local $y i64)
-  (local $z f32)
-  (local $w f64)
-  (local $4 i32)
-  (local.set $4
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $4)
-    (i32.const 16)
-   )
-  )
-  (block
-   (local.set $x
-    (i32.const 1)
-   )
-   (local.set $y
-    (i64.const 1)
-   )
-   (local.set $z
-    (f32.const 1)
-   )
-   (local.set $w
-    (f64.const 1)
-   )
-   (block
-    (i32.store
-     (local.get $4)
-     (local.get $x)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-   (drop
-    (local.get $y)
-   )
-   (drop
-    (local.get $z)
-   )
-   (drop
-    (local.get $w)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $4)
-  )
- )
- (func $spill4
-  (local $x i32)
-  (local $y i32)
-  (local $z i32)
-  (local $w i32)
-  (local $4 i32)
-  (local.set $4
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $4)
-    (i32.const 16)
-   )
-  )
-  (block
-   (local.set $x
-    (i32.const 1)
-   )
-   (local.set $y
-    (i32.const 1)
-   )
-   (local.set $z
-    (i32.const 1)
-   )
-   (local.set $w
-    (i32.const 1)
-   )
-   (block
-    (i32.store
-     (local.get $4)
-     (local.get $x)
-    )
-    (i32.store offset=4
-     (local.get $4)
-     (local.get $y)
-    )
-    (i32.store offset=8
-     (local.get $4)
-     (local.get $z)
-    )
-    (i32.store offset=12
-     (local.get $4)
-     (local.get $w)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-   (drop
-    (local.get $y)
-   )
-   (drop
-    (local.get $z)
-   )
-   (drop
-    (local.get $w)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $4)
-  )
- )
- (func $spill5
-  (local $x i32)
-  (local $y i32)
-  (local $z i32)
-  (local $w i32)
-  (local $a i32)
-  (local $5 i32)
-  (local.set $5
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $5)
-    (i32.const 32)
-   )
-  )
-  (block
-   (local.set $x
-    (i32.const 1)
-   )
-   (local.set $y
-    (i32.const 1)
-   )
-   (local.set $z
-    (i32.const 1)
-   )
-   (local.set $w
-    (i32.const 1)
-   )
-   (local.set $a
-    (i32.const 1)
-   )
-   (block
-    (i32.store
-     (local.get $5)
-     (local.get $x)
-    )
-    (i32.store offset=4
-     (local.get $5)
-     (local.get $y)
-    )
-    (i32.store offset=8
-     (local.get $5)
-     (local.get $z)
-    )
-    (i32.store offset=12
-     (local.get $5)
-     (local.get $w)
-    )
-    (i32.store offset=16
-     (local.get $5)
-     (local.get $a)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-   (drop
-    (local.get $y)
-   )
-   (drop
-    (local.get $z)
-   )
-   (drop
-    (local.get $w)
-   )
-   (drop
-    (local.get $a)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $5)
-  )
- )
- (func $some-alive
-  (local $x i32)
-  (local $y i32)
-  (local $2 i32)
-  (local.set $2
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $2)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (i32.store
-     (local.get $2)
-     (local.get $x)
-    )
-    (call $nothing)
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $2)
-  )
- )
- (func $spill-args (param $p i32) (param $q i32)
-  (local $x i32)
-  (local $3 i32)
-  (local $4 i32)
-  (local $5 i32)
-  (local.set $3
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $3)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (local.set $4
-     (i32.const 1)
-    )
-    (local.set $5
-     (i32.const 2)
-    )
-    (i32.store offset=8
-     (local.get $3)
-     (local.get $x)
-    )
-    (call $spill-args
-     (local.get $4)
-     (local.get $5)
-    )
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $3)
-  )
- )
- (func $spill-ret (result i32)
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local $3 i32)
-  (local $4 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (local.set $4
-   (block (result i32)
-    (block
-     (i32.store
-      (local.get $1)
-      (local.get $x)
-     )
-     (call $nothing)
-    )
-    (drop
-     (local.get $x)
-    )
-    (if
-     (i32.const 1)
-     (block
-      (local.set $2
-       (i32.const 2)
-      )
-      (global.set $stack_ptr
-       (local.get $1)
-      )
-      (return
-       (local.get $2)
-      )
-     )
-     (block
-      (local.set $3
-       (i32.const 3)
-      )
-      (global.set $stack_ptr
-       (local.get $1)
-      )
-      (return
-       (local.get $3)
-      )
-     )
-    )
-    (i32.const 4)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
-  (local.get $4)
- )
- (func $spill-unreachable (result i32)
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (local.set $2
-   (block (result i32)
-    (block
-     (i32.store
-      (local.get $1)
-      (local.get $x)
-     )
-     (call $nothing)
-    )
-    (drop
-     (local.get $x)
-    )
-    (unreachable)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
-  (local.get $2)
- )
- (func $spill-call-call0 (param $p i32) (result i32)
-  (unreachable)
- )
- (func $spill-call-call1 (param $p i32) (result i32)
-  (local $x i32)
-  (local $2 i32)
-  (local $3 i32)
-  (local $4 i32)
-  (local $5 i32)
-  (local.set $2
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $2)
-    (i32.const 16)
-   )
-  )
-  (local.set $5
-   (block (result i32)
-    (drop
-     (block (result i32)
-      (local.set $3
-       (block (result i32)
-        (local.set $4
-         (i32.const 1)
-        )
-        (i32.store offset=4
-         (local.get $2)
-         (local.get $x)
-        )
-        (call $spill-call-call1
-         (local.get $4)
-        )
-       )
-      )
-      (i32.store offset=4
-       (local.get $2)
-       (local.get $x)
-      )
-      (call $spill-call-call0
-       (local.get $3)
-      )
-     )
-    )
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $2)
-  )
-  (local.get $5)
- )
- (func $spill-call-ret (param $p i32) (result i32)
-  (local $x i32)
-  (drop
-   (call $spill-call-call0
-    (return
-     (i32.const 1)
-    )
-   )
-  )
-  (i32.const 0)
- )
- (func $spill-ret-call (param $p i32) (result i32)
-  (local $x i32)
-  (drop
-   (return
-    (call $spill-call-call0
-     (i32.const 1)
-    )
-   )
-  )
-  (i32.const 0)
- )
- (func $spill-ret-ret (result i32)
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local $3 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (local.set $3
-   (block (result i32)
-    (block
-     (i32.store
-      (local.get $1)
-      (local.get $x)
-     )
-     (call $nothing)
-    )
-    (drop
-     (local.get $x)
-    )
-    (drop
-     (block
-      (global.set $stack_ptr
-       (local.get $1)
-      )
-      (return
-       (block
-        (local.set $2
-         (i32.const 1)
-        )
-        (global.set $stack_ptr
-         (local.get $1)
-        )
-        (return
-         (local.get $2)
-        )
-       )
-      )
-     )
-    )
-    (i32.const 0)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
-  (local.get $3)
- )
- (func $spill-call-othertype (param $y f64)
-  (local $x i32)
-  (local $2 i32)
-  (local $3 f64)
-  (local.set $2
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $2)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (local.set $3
-     (f64.const 1)
-    )
-    (i32.store
-     (local.get $2)
-     (local.get $x)
-    )
-    (call $spill-call-othertype
-     (local.get $3)
-    )
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $2)
-  )
- )
- (func $spill-call_indirect
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local $3 i32)
-  (local $4 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (local.set $2
-     (i32.const 123)
-    )
-    (local.set $3
-     (i32.const 456)
-    )
-    (local.set $4
-     (i32.const 789)
-    )
-    (i32.store
-     (local.get $1)
-     (local.get $x)
-    )
-    (call_indirect (type $i32_i32_=>_none)
-     (local.get $2)
-     (local.get $3)
-     (local.get $4)
-    )
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
- )
- (func $spill-call_import
-  (local $x i32)
-  (local $1 i32)
-  (local $2 i32)
-  (local.set $1
-   (global.get $stack_ptr)
-  )
-  (global.set $stack_ptr
-   (i32.add
-    (local.get $1)
-    (i32.const 16)
-   )
-  )
-  (block
-   (block
-    (local.set $2
-     (i32.const 200)
-    )
-    (i32.store
-     (local.get $1)
-     (local.get $x)
-    )
-    (call $segfault
-     (local.get $2)
-    )
-   )
-   (drop
-    (local.get $x)
-   )
-  )
-  (global.set $stack_ptr
-   (local.get $1)
-  )
- )
-)
diff --git a/binaryen/test/passes/spill-pointers.wast b/binaryen/test/passes/spill-pointers.wast
deleted file mode 100644
--- a/binaryen/test/passes/spill-pointers.wast
+++ /dev/null
@@ -1,338 +0,0 @@
-(module
-  (memory 10)
-  (type $ii (func (param i32 i32)))
-  (table 1 1 funcref)
-  (elem (i32.const 0))
-  (import "env" "STACKTOP" (global $STACKTOP$asm2wasm$import i32))
-  (import "env" "segfault" (func $segfault (param i32)))
-  (global $stack_ptr (mut i32) (global.get $STACKTOP$asm2wasm$import))
-
-  (func $nothing
-  )
-  (func $not-alive
-    (local $x i32)
-    (local.set $x (i32.const 1))
-    (call $nothing)
-  )
-  (func $spill
-    (local $x i32)
-    (call $nothing)
-    (drop (local.get $x))
-  )
-  (func $ignore-non-pointers
-    (local $x i32)
-    (local $y i64)
-    (local $z f32)
-    (local $w f64)
-    (local.set $x (i32.const 1))
-    (local.set $y (i64.const 1))
-    (local.set $z (f32.const 1))
-    (local.set $w (f64.const 1))
-    (call $nothing)
-    (drop (local.get $x))
-    (drop (local.get $y))
-    (drop (local.get $z))
-    (drop (local.get $w))
-  )
-  (func $spill4
-    (local $x i32)
-    (local $y i32)
-    (local $z i32)
-    (local $w i32)
-    (local.set $x (i32.const 1))
-    (local.set $y (i32.const 1))
-    (local.set $z (i32.const 1))
-    (local.set $w (i32.const 1))
-    (call $nothing)
-    (drop (local.get $x))
-    (drop (local.get $y))
-    (drop (local.get $z))
-    (drop (local.get $w))
-  )
-  (func $spill5
-    (local $x i32)
-    (local $y i32)
-    (local $z i32)
-    (local $w i32)
-    (local $a i32)
-    (local.set $x (i32.const 1))
-    (local.set $y (i32.const 1))
-    (local.set $z (i32.const 1))
-    (local.set $w (i32.const 1))
-    (local.set $a (i32.const 1))
-    (call $nothing)
-    (drop (local.get $x))
-    (drop (local.get $y))
-    (drop (local.get $z))
-    (drop (local.get $w))
-    (drop (local.get $a))
-  )
-  (func $some-alive
-    (local $x i32)
-    (local $y i32)
-    (call $nothing)
-    (drop (local.get $x))
-  )
-  (func $spill-args (param $p i32) (param $q i32)
-    (local $x i32)
-    (call $spill-args (i32.const 1) (i32.const 2))
-    (drop (local.get $x))
-  )
-  (func $spill-ret (result i32)
-    (local $x i32)
-    (call $nothing)
-    (drop (local.get $x))
-    (if (i32.const 1)
-      (return (i32.const 2))
-      (return (i32.const 3))
-    )
-    (i32.const 4)
-  )
-  (func $spill-unreachable (result i32)
-    (local $x i32)
-    (call $nothing)
-    (drop (local.get $x))
-    (unreachable)
-  )
-  (func $spill-call-call0 (param $p i32) (result i32)
-    (unreachable)
-  )
-  (func $spill-call-call1 (param $p i32) (result i32)
-    (local $x i32)
-    (drop
-      (call $spill-call-call0
-        (call $spill-call-call1
-          (i32.const 1)
-        )
-      )
-    )
-    (local.get $x)
-  )
-  (func $spill-call-ret (param $p i32) (result i32)
-    (local $x i32)
-    (drop
-      (call $spill-call-call0
-        (return
-          (i32.const 1)
-        )
-      )
-    )
-    (local.get $x)
-  )
-  (func $spill-ret-call (param $p i32) (result i32)
-    (local $x i32)
-    (drop
-      (return
-        (call $spill-call-call0
-          (i32.const 1)
-        )
-      )
-    )
-    (local.get $x)
-  )
-  (func $spill-ret-ret (result i32)
-    (local $x i32)
-    (call $nothing)
-    (drop (local.get $x))
-    (drop
-      (return
-        (return
-          (i32.const 1)
-        )
-      )
-    )
-    (local.get $x)
-  )
-  (func $spill-call-othertype (param $y f64)
-    (local $x i32)
-    (call $spill-call-othertype (f64.const 1))
-    (drop (local.get $x))
-  )
-  (func $spill-call_indirect
-    (local $x i32)
-    (call_indirect (type $ii)
-      (i32.const 123)
-      (i32.const 456)
-      (i32.const 789)
-    )
-    (drop (local.get $x))
-  )
-  (func $spill-call_import
-    (local $x i32)
-    (call $segfault
-      (i32.const 200)
-    )
-    (drop (local.get $x))
-  )
-)
-
-(module
-  (memory 10)
-  (type $ii (func (param i32 i32)))
-  (table 1 1 funcref)
-  (elem (i32.const 0))
-  (global $stack_ptr (mut i32) (i32.const 1716592))
-  (export "stackSave" (func $stack_save))
-  (import "env" "segfault" (func $segfault (param i32)))
-  (func $stack_save (result i32)
-    (global.get $stack_ptr)
-  )
-
-  (func $nothing
-  )
-  (func $not-alive
-    (local $x i32)
-    (local.set $x (i32.const 1))
-    (call $nothing)
-  )
-  (func $spill
-    (local $x i32)
-    (call $nothing)
-    (drop (local.get $x))
-  )
-  (func $ignore-non-pointers
-    (local $x i32)
-    (local $y i64)
-    (local $z f32)
-    (local $w f64)
-    (local.set $x (i32.const 1))
-    (local.set $y (i64.const 1))
-    (local.set $z (f32.const 1))
-    (local.set $w (f64.const 1))
-    (call $nothing)
-    (drop (local.get $x))
-    (drop (local.get $y))
-    (drop (local.get $z))
-    (drop (local.get $w))
-  )
-  (func $spill4
-    (local $x i32)
-    (local $y i32)
-    (local $z i32)
-    (local $w i32)
-    (local.set $x (i32.const 1))
-    (local.set $y (i32.const 1))
-    (local.set $z (i32.const 1))
-    (local.set $w (i32.const 1))
-    (call $nothing)
-    (drop (local.get $x))
-    (drop (local.get $y))
-    (drop (local.get $z))
-    (drop (local.get $w))
-  )
-  (func $spill5
-    (local $x i32)
-    (local $y i32)
-    (local $z i32)
-    (local $w i32)
-    (local $a i32)
-    (local.set $x (i32.const 1))
-    (local.set $y (i32.const 1))
-    (local.set $z (i32.const 1))
-    (local.set $w (i32.const 1))
-    (local.set $a (i32.const 1))
-    (call $nothing)
-    (drop (local.get $x))
-    (drop (local.get $y))
-    (drop (local.get $z))
-    (drop (local.get $w))
-    (drop (local.get $a))
-  )
-  (func $some-alive
-    (local $x i32)
-    (local $y i32)
-    (call $nothing)
-    (drop (local.get $x))
-  )
-  (func $spill-args (param $p i32) (param $q i32)
-    (local $x i32)
-    (call $spill-args (i32.const 1) (i32.const 2))
-    (drop (local.get $x))
-  )
-  (func $spill-ret (result i32)
-    (local $x i32)
-    (call $nothing)
-    (drop (local.get $x))
-    (if (i32.const 1)
-      (return (i32.const 2))
-      (return (i32.const 3))
-    )
-    (i32.const 4)
-  )
-  (func $spill-unreachable (result i32)
-    (local $x i32)
-    (call $nothing)
-    (drop (local.get $x))
-    (unreachable)
-  )
-  (func $spill-call-call0 (param $p i32) (result i32)
-    (unreachable)
-  )
-  (func $spill-call-call1 (param $p i32) (result i32)
-    (local $x i32)
-    (drop
-      (call $spill-call-call0
-        (call $spill-call-call1
-          (i32.const 1)
-        )
-      )
-    )
-    (local.get $x)
-  )
-  (func $spill-call-ret (param $p i32) (result i32)
-    (local $x i32)
-    (drop
-      (call $spill-call-call0
-        (return
-          (i32.const 1)
-        )
-      )
-    )
-    (local.get $x)
-  )
-  (func $spill-ret-call (param $p i32) (result i32)
-    (local $x i32)
-    (drop
-      (return
-        (call $spill-call-call0
-          (i32.const 1)
-        )
-      )
-    )
-    (local.get $x)
-  )
-  (func $spill-ret-ret (result i32)
-    (local $x i32)
-    (call $nothing)
-    (drop (local.get $x))
-    (drop
-      (return
-        (return
-          (i32.const 1)
-        )
-      )
-    )
-    (local.get $x)
-  )
-  (func $spill-call-othertype (param $y f64)
-    (local $x i32)
-    (call $spill-call-othertype (f64.const 1))
-    (drop (local.get $x))
-  )
-  (func $spill-call_indirect
-    (local $x i32)
-    (call_indirect (type $ii)
-      (i32.const 123)
-      (i32.const 456)
-      (i32.const 789)
-    )
-    (drop (local.get $x))
-  )
-  (func $spill-call_import
-    (local $x i32)
-    (call $segfault
-      (i32.const 200)
-    )
-    (drop (local.get $x))
-  )
-)
diff --git a/binaryen/test/passes/stack-check_enable-mutable-globals.txt b/binaryen/test/passes/stack-check_enable-mutable-globals.txt
--- a/binaryen/test/passes/stack-check_enable-mutable-globals.txt
+++ b/binaryen/test/passes/stack-check_enable-mutable-globals.txt
@@ -39,3 +39,25 @@
   )
  )
 )
+(module
+ (type $i32_i32_=>_none (func (param i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (global $__stack_base (mut i32) (i32.const 0))
+ (global $__stack_limit (mut i32) (i32.const 0))
+ (global $__stack_base_0 (mut i32) (i32.const 0))
+ (global $__stack_limit_0 (mut i32) (i32.const 0))
+ (export "use_stack" (func $0))
+ (export "__set_stack_limits" (func $__set_stack_limits))
+ (func $0 (result i32)
+  (unreachable)
+ )
+ (func $__set_stack_limits (param $0 i32) (param $1 i32)
+  (global.set $__stack_base_0
+   (local.get $0)
+  )
+  (global.set $__stack_limit_0
+   (local.get $1)
+  )
+ )
+)
diff --git a/binaryen/test/passes/stack-check_enable-mutable-globals.wast b/binaryen/test/passes/stack-check_enable-mutable-globals.wast
--- a/binaryen/test/passes/stack-check_enable-mutable-globals.wast
+++ b/binaryen/test/passes/stack-check_enable-mutable-globals.wast
@@ -5,3 +5,13 @@
   (global.get $sp)
  )
 )
+;; if the global names are taken we should not crash
+(module
+ (import "env" "__stack_pointer" (global $sp (mut i32)))
+ (global $__stack_base (mut i32) (i32.const 0))
+ (global $__stack_limit (mut i32) (i32.const 0))
+ (export "use_stack" (func $0))
+ (func $0 (result i32)
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/passes/strip-debug.bin.txt b/binaryen/test/passes/strip-debug.bin.txt
--- a/binaryen/test/passes/strip-debug.bin.txt
+++ b/binaryen/test/passes/strip-debug.bin.txt
@@ -1,7 +1,7 @@
 (module
  (type $none_=>_i32 (func (result i32)))
  (import "env" "__linear_memory" (memory $mimport$0 0))
- (import "env" "__indirect_function_table" (table $timport$1 0 funcref))
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
  (func $0 (result i32)
   (local $0 i32)
   (local.set $0
diff --git a/binaryen/test/passes/strip-producers.bin.txt b/binaryen/test/passes/strip-producers.bin.txt
--- a/binaryen/test/passes/strip-producers.bin.txt
+++ b/binaryen/test/passes/strip-producers.bin.txt
@@ -1,7 +1,7 @@
 (module
  (type $none_=>_i32 (func (result i32)))
  (import "env" "__linear_memory" (memory $mimport$0 0))
- (import "env" "__indirect_function_table" (table $timport$1 0 funcref))
+ (import "env" "__indirect_function_table" (table $timport$0 0 funcref))
  (func $0 (result i32)
   (local $0 i32)
   (local.set $0
diff --git a/binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.txt b/binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.txt
--- a/binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.txt
+++ b/binaryen/test/passes/strip-target-features_roundtrip_print-features_all-features.txt
@@ -10,6 +10,7 @@
 --enable-multivalue
 --enable-gc
 --enable-memory64
+--enable-typed-function-references
 (module
  (type $none_=>_v128_externref (func (result v128 externref)))
  (func $foo (result v128 externref)
diff --git a/binaryen/test/passes/translate-to-fuzz_all-features.txt b/binaryen/test/passes/translate-to-fuzz_all-features.txt
--- a/binaryen/test/passes/translate-to-fuzz_all-features.txt
+++ b/binaryen/test/passes/translate-to-fuzz_all-features.txt
@@ -1,1013 +1,1138 @@
 (module
- (type $none_=>_none (func))
- (type $none_=>_i32 (func (result i32)))
- (type $i64_=>_none (func (param i64)))
- (type $i32_=>_none (func (param i32)))
- (type $f32_=>_none (func (param f32)))
- (type $f64_=>_none (func (param f64)))
- (type $v128_=>_none (func (param v128)))
- (type $exnref_=>_none (func (param exnref)))
- (type $funcref_f64_=>_i32 (func (param funcref f64) (result i32)))
- (type $none_=>_f32 (func (result f32)))
- (type $eqref_i32_=>_funcref (func (param eqref i32) (result funcref)))
- (type $i32_i32_f32_exnref_=>_externref (func (param i32 i32 f32 exnref) (result externref)))
- (type $externref_f64_f32_eqref_i31ref_anyref_=>_externref (func (param externref f64 f32 eqref i31ref anyref) (result externref)))
- (type $exnref_f32_i31ref_externref_funcref_i31ref_i64_=>_exnref (func (param exnref f32 i31ref externref funcref i31ref i64) (result exnref)))
- (type $none_=>_eqref_i31ref_i64_v128_eqref (func (result eqref i31ref i64 v128 eqref)))
- (type $v128_i31ref_=>_eqref_i31ref_i64_v128_eqref (func (param v128 i31ref) (result eqref i31ref i64 v128 eqref)))
- (type $none_=>_i31ref (func (result i31ref)))
- (import "fuzzing-support" "log-i32" (func $log-i32 (param i32)))
- (import "fuzzing-support" "log-i64" (func $log-i64 (param i64)))
- (import "fuzzing-support" "log-f32" (func $log-f32 (param f32)))
- (import "fuzzing-support" "log-f64" (func $log-f64 (param f64)))
- (import "fuzzing-support" "log-v128" (func $log-v128 (param v128)))
- (import "fuzzing-support" "log-exnref" (func $log-exnref (param exnref)))
- (memory $0 (shared 1 1))
- (data (i32.const 0) "N\0fN\f5\f9\b1\ff\fa\eb\e5\fe\a7\ec\fb\fc\f4\a6\e4\ea\f0\ae\e3")
- (table $0 5 5 funcref)
- (elem (i32.const 0) $func_9 $func_9 $func_9 $func_10 $func_14)
- (global $global$5 (mut eqref) (ref.null eq))
- (global $global$4 (mut i32) (i32.const 470177031))
- (global $global$3 (mut f64) (f64.const 2147483647))
- (global $global$2 (mut (eqref f32 eqref funcref funcref i64)) (tuple.make
-  (ref.null eq)
-  (f32.const -2147483648)
-  (ref.null eq)
-  (ref.null func)
-  (ref.null func)
-  (i64.const -32)
- ))
- (global $global$1 (mut f32) (f32.const -32769))
- (global $hangLimit (mut i32) (i32.const 10))
- (export "hashMemory" (func $hashMemory))
- (export "memory" (memory $0))
- (export "func_7_invoker" (func $func_7_invoker))
- (export "func_9" (func $func_9))
- (export "func_11_invoker" (func $func_11_invoker))
- (export "func_14" (func $func_14))
- (export "func_18" (func $func_18))
- (export "func_19" (func $func_19))
- (export "hangLimitInitializer" (func $hangLimitInitializer))
- (func $hashMemory (result i32)
-  (local $0 i32)
-  (local.set $0
-   (i32.const 5381)
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=1
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=2
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=3
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=4
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=5
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=6
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=7
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=8
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=9
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=10
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=11
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=12
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=13
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=14
-     (i32.const 0)
-    )
-   )
-  )
-  (local.set $0
-   (i32.xor
-    (i32.add
-     (i32.shl
-      (local.get $0)
-      (i32.const 5)
-     )
-     (local.get $0)
-    )
-    (i32.load8_u offset=15
-     (i32.const 0)
-    )
-   )
-  )
-  (local.get $0)
- )
- (func $func_7 (param $0 i32) (param $1 i32) (param $2 f32) (param $3 exnref) (result externref)
-  (local $4 i32)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (ref.null extern)
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (ref.null extern)
- )
- (func $func_7_invoker
-  (drop
-   (call $func_7
-    (i32.const -127)
-    (i32.const -268435456)
-    (f32.const 1179405440)
-    (ref.null exn)
-   )
-  )
-  (call $log-i32
-   (call $hashMemory)
-  )
- )
- (func $func_9 (result f32)
-  (local $0 anyref)
-  (local $1 f64)
-  (local $2 (anyref anyref))
-  (local $3 eqref)
-  (local $4 externref)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (f32.const 1.4949444621624858e-31)
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (block $label$0
-   (nop)
-   (block $label$1
-    (nop)
-    (return
-     (f32.const 7.396028525772014e-24)
-    )
-   )
-  )
- )
- (func $func_10 (param $0 externref) (param $1 f64) (param $2 f32) (param $3 eqref) (param $4 i31ref) (param $5 anyref) (result externref)
-  (local $6 i64)
-  (local $7 (anyref exnref f32 f64 f64))
-  (local $8 eqref)
-  (local $9 exnref)
-  (local $10 i64)
-  (local $11 f64)
-  (local $12 f32)
-  (local $13 v128)
-  (local $14 exnref)
-  (local $15 (funcref funcref v128 i31ref v128))
-  (local $16 anyref)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (ref.null extern)
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (ref.null extern)
- )
- (func $func_11 (param $0 exnref) (param $1 f32) (param $2 i31ref) (param $3 externref) (param $4 funcref) (param $5 i31ref) (param $6 i64) (result exnref)
-  (local $7 (i32 i64 anyref externref externref eqref))
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (ref.null exn)
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (ref.null exn)
- )
- (func $func_11_invoker
-  (drop
-   (call $func_11
-    (ref.null exn)
-    (f32.const -1022.1400146484375)
-    (i31.new
-     (i32.const -32766)
-    )
-    (ref.null extern)
-    (ref.null func)
-    (i31.new
-     (i32.const -65535)
-    )
-    (i64.const 3)
-   )
-  )
-  (call $log-i32
-   (call $hashMemory)
-  )
- )
- (func $func_13 (result i31ref)
-  (local $0 i31ref)
-  (local $1 (funcref f32 anyref f32 externref))
-  (local $2 f64)
-  (local $3 f64)
-  (local $4 (i32 v128))
-  (local $5 (anyref i64 v128 eqref funcref exnref))
-  (local $6 i32)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (i31.new
-      (i32.const -28)
-     )
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (i31.new
-   (i32.const 64)
-  )
- )
- (func $func_14 (result i32)
-  (local $0 i32)
-  (local $1 funcref)
-  (local $2 (anyref externref))
-  (local $3 funcref)
-  (local $4 i64)
-  (local $5 externref)
-  (local $6 (exnref f64))
-  (local $7 (anyref f64 f64))
-  (local $8 (i64 i32 eqref exnref))
-  (local $9 (v128 i64 funcref i32 anyref anyref))
-  (local $10 (i32 eqref f64 funcref))
-  (local $11 eqref)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (local.get $0)
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (block $label$0 (result i32)
-   (nop)
-   (local.get $0)
-  )
- )
- (func $func_15 (result i32)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (i32.const 32768)
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (global.get $global$4)
- )
- (func $func_16 (param $0 eqref) (param $1 i32) (result funcref)
-  (local $2 v128)
-  (local $3 funcref)
-  (local $4 eqref)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (local.get $3)
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (loop $label$1 (result funcref)
-   (block
-    (if
-     (i32.eqz
-      (global.get $hangLimit)
-     )
-     (return
-      (local.get $3)
-     )
-    )
-    (global.set $hangLimit
-     (i32.sub
-      (global.get $hangLimit)
-      (i32.const 1)
-     )
-    )
-   )
-   (block (result funcref)
-    (block $label$2
-     (br_if $label$2
-      (i32.eqz
-       (block $label$3
-        (global.set $global$4
-         (local.tee $1
-          (local.get $1)
-         )
-        )
-        (block $label$4
-         (nop)
-         (br_if $label$1
-          (i32.eqz
-           (i31.get_u
-            (i31.new
-             (i32.const -90)
-            )
-           )
-          )
-         )
-        )
-        (br $label$1)
-       )
-      )
-     )
-     (memory.init 0
-      (i32.and
-       (local.get $1)
-       (i32.const 15)
-      )
-      (i32.const 16)
-      (i32.const 3)
-     )
-    )
-    (br_if $label$1
-     (i32.const 131071)
-    )
-    (local.get $3)
-   )
-  )
- )
- (func $func_17 (param $0 i64)
-  (local $1 externref)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return)
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (block $label$0
-   (call $log-i32
-    (call $hashMemory)
-   )
-   (if
-    (i32.eqz
-     (f64.gt
-      (f64.const 103)
-      (f64.max
-       (f64.const 8388607.124)
-       (if
-        (i32.eqz
-         (global.get $global$4)
-        )
-        (block $label$1
-         (call $log-v128
-          (f64x2.replace_lane 0
-           (f32x4.neg
-            (i8x16.shr_u
-             (v128.load offset=3
-              (i32.const 65535)
-             )
-             (loop $label$2 (result i32)
-              (block
-               (if
-                (i32.eqz
-                 (global.get $hangLimit)
-                )
-                (return)
-               )
-               (global.set $hangLimit
-                (i32.sub
-                 (global.get $hangLimit)
-                 (i32.const 1)
-                )
-               )
-              )
-              (block (result i32)
-               (block $label$3
-                (call $log-exnref
-                 (ref.null exn)
-                )
-                (call $log-i32
-                 (i32.atomic.rmw8.sub_u offset=22
-                  (i32.and
-                   (i32.const 6)
-                   (i32.const 15)
-                  )
-                  (i32.const 1852667194)
-                 )
-                )
-               )
-               (br_if $label$2
-                (tuple.extract 0
-                 (tuple.make
-                  (i32.const -2147483648)
-                  (i31.new
-                   (i32.const -32767)
-                  )
-                 )
-                )
-               )
-               (i32.const -2147483648)
-              )
-             )
-            )
-           )
-           (f64.const -nan:0xffffffffffff3)
-          )
-         )
-         (br $label$0)
-        )
-        (block $label$4
-         (br_if $label$0
-          (i32.eqz
-           (tuple.extract 2
-            (block $label$5
-             (call $log-i32
-              (call $hashMemory)
-             )
-             (br $label$0)
-            )
-           )
-          )
-         )
-         (br $label$0)
-        )
-       )
-      )
-     )
-    )
-    (block $label$6
-     (call $log-i32
-      (call $hashMemory)
-     )
-     (call $log-i32
-      (call $hashMemory)
-     )
-    )
-    (if
-     (i32.eqz
-      (i32.or
-       (i32.const 65535)
-       (i32.const 8)
-      )
-     )
-     (call $log-i32
-      (i32.const 608321884)
-     )
-     (atomic.fence)
-    )
-   )
-  )
- )
- (func $func_18 (param $0 v128) (param $1 i31ref) (result eqref i31ref i64 v128 eqref)
-  (local $2 i64)
-  (local $3 v128)
-  (local $4 f32)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (tuple.make
-      (ref.null eq)
-      (i31.new
-       (i32.const -2147483648)
-      )
-      (i64.const 369041285507055655)
-      (v128.const i32x4 0xffffffd1 0xffffffff 0x25312936 0x5455263f)
-      (ref.null eq)
-     )
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (tuple.make
-   (ref.null eq)
-   (local.get $1)
-   (i64.const -32766)
-   (v128.bitselect
-    (local.get $3)
-    (block $label$2
-     (atomic.fence)
-     (return
-      (tuple.make
-       (ref.null eq)
-       (i31.new
-        (i32.const 19521)
-       )
-       (i64.const -32766)
-       (v128.const i32x4 0x4f800000 0x3e116873 0x46ca0800 0x54000000)
-       (ref.null eq)
-      )
-     )
-    )
-    (tuple.extract 2
-     (tuple.make
-      (i31.new
-       (i32.const 1684216173)
-      )
-      (ref.null eq)
-      (v128.const i32x4 0xffa20004 0x00000000 0x2b25ffa6 0x005b0080)
-      (ref.null eq)
-     )
-    )
-   )
-   (global.get $global$5)
-  )
- )
- (func $func_19 (param $0 funcref) (param $1 f64) (result i32)
-  (local $2 (funcref f32 exnref exnref externref))
-  (local $3 externref)
-  (local $4 v128)
-  (local $5 f64)
-  (local $6 i32)
-  (local $7 (f64 i31ref eqref eqref))
-  (local $8 anyref)
-  (local $9 (eqref i31ref i32 i31ref anyref))
-  (local $10 eqref)
-  (local $11 exnref)
-  (local $12 externref)
-  (local $13 externref)
-  (local $14 externref)
-  (local $15 i31ref)
-  (block
-   (if
-    (i32.eqz
-     (global.get $hangLimit)
-    )
-    (return
-     (i32.const -131072)
-    )
-   )
-   (global.set $hangLimit
-    (i32.sub
-     (global.get $hangLimit)
-     (i32.const 1)
-    )
-   )
-  )
-  (select
-   (i32.atomic.load8_u offset=22
-    (i32.and
-     (local.get $6)
-     (i32.const 15)
-    )
-   )
-   (local.tee $6
-    (select
-     (i16x8.extract_lane_s 4
-      (v128.const i32x4 0xfffffff8 0x00008001 0xffffffa0 0x180b1217)
-     )
-     (if (result i32)
-      (if (result i32)
-       (i32.eqz
-        (i32.const 524287)
-       )
-       (block $label$1
-        (memory.init 0
-         (i32.and
-          (f32.ge
-           (block $label$2 (result f32)
-            (call $log-i32
-             (call $hashMemory)
-            )
-            (if (result f32)
-             (if (result i32)
-              (i32.eqz
-               (loop $label$3 (result i32)
-                (block
-                 (if
-                  (i32.eqz
-                   (global.get $hangLimit)
-                  )
-                  (return
-                   (i32.const -83)
-                  )
-                 )
-                 (global.set $hangLimit
-                  (i32.sub
-                   (global.get $hangLimit)
-                   (i32.const 1)
-                  )
-                 )
-                )
-                (block (result i32)
-                 (br_if $label$3
-                  (local.get $6)
-                 )
-                 (br_if $label$3
-                  (local.get $6)
-                 )
-                 (i32.const -33)
-                )
-               )
-              )
-              (i32.const 2147483647)
-              (if (result i32)
-               (i32.eqz
-                (i32.const 32768)
-               )
-               (i32.const 16404)
-               (i32.const -1024)
-              )
-             )
-             (f32.const -nan:0x7fffa8)
-             (block $label$4 (result f32)
-              (call $log-i32
-               (call $hashMemory)
-              )
-              (f32.const 18446744073709551615)
-             )
-            )
-           )
-           (if (result f32)
-            (i32.eqz
-             (ref.is_null
-              (if (result externref)
-               (i32.eqz
-                (i32.const -65535)
-               )
-               (ref.null extern)
-               (local.get $12)
-              )
-             )
-            )
-            (block $label$5 (result f32)
-             (call $log-f32
-              (select
-               (f32.const 4096)
-               (f32.const -nan:0x7fffa1)
-               (i32.const 2097640319)
-              )
-             )
-             (f32.const 8192)
-            )
-            (f32.const -1125899906842624)
-           )
-          )
-          (i32.const 15)
-         )
-         (i32.const 1)
-         (i32.const 2)
-        )
-        (return
-         (local.get $6)
-        )
-       )
-       (block $label$6 (result i32)
-        (loop $label$7
-         (block
-          (if
-           (i32.eqz
-            (global.get $hangLimit)
-           )
-           (return
-            (i32.const -4096)
-           )
-          )
-          (global.set $hangLimit
-           (i32.sub
-            (global.get $hangLimit)
-            (i32.const 1)
-           )
-          )
-         )
-         (block $label$8
-          (nop)
-          (memory.fill
-           (i32.and
-            (i8x16.extract_lane_s 11
-             (i8x16.max_s
-              (local.get $4)
-              (i16x8.add_saturate_u
-               (v128.const i32x4 0xffea0f4a 0xfdffffec 0xdfff0512 0x1910ffff)
-               (local.get $4)
-              )
-             )
-            )
-            (i32.const 15)
-           )
-           (i32.const 1326258715)
-           (local.get $6)
-          )
-         )
-        )
-        (local.get $6)
-       )
-      )
-      (block $label$9 (result i32)
-       (i32.const 10353)
-      )
-      (local.get $6)
-     )
-     (select
-      (i32.const 33554433)
-      (i32.trunc_f64_s
-       (f64.const 3402823466385288598117041e14)
-      )
-      (local.tee $6
-       (select
-        (local.get $6)
-        (ref.eq
-         (loop $label$0 (result i31ref)
-          (block
-           (if
-            (i32.eqz
-             (global.get $hangLimit)
-            )
-            (return
-             (i32.const -32768)
-            )
-           )
-           (global.set $hangLimit
-            (i32.sub
-             (global.get $hangLimit)
-             (i32.const 1)
-            )
-           )
-          )
-          (block (result i31ref)
-           (local.set $5
-            (f64.const 371920655)
-           )
-           (br_if $label$0
-            (i32.eqz
-             (local.tee $6
-              (local.tee $6
-               (local.tee $6
-                (local.tee $6
-                 (local.get $6)
-                )
-               )
-              )
-             )
-            )
-           )
-           (local.get $15)
-          )
-         )
-         (local.get $10)
-        )
-        (local.get $6)
-       )
-      )
-     )
-    )
-   )
-   (global.get $global$4)
+ (type $none_=>_i32_v128_f64_v128 (func (result i32 v128 f64 v128)))
+ (type $none_=>_none (func))
+ (type $i32_=>_none (func (param i32)))
+ (type $i64_=>_none (func (param i64)))
+ (type $i64_i32_=>_none (func (param i64 i32)))
+ (type $f32_=>_none (func (param f32)))
+ (type $f64_=>_none (func (param f64)))
+ (type $v128_=>_none (func (param v128)))
+ (type $exnref_=>_none (func (param exnref)))
+ (type $none_=>_i32 (func (result i32)))
+ (import "fuzzing-support" "log-i32" (func $log-i32 (param i32)))
+ (import "fuzzing-support" "log-i64" (func $log-i64 (param i64)))
+ (import "fuzzing-support" "log-f32" (func $log-f32 (param f32)))
+ (import "fuzzing-support" "log-f64" (func $log-f64 (param f64)))
+ (import "fuzzing-support" "log-v128" (func $log-v128 (param v128)))
+ (import "fuzzing-support" "log-exnref" (func $log-exnref (param exnref)))
+ (memory $0 (shared 16 17))
+ (data (i32.const 0) "N\0fN\f5\f9\b1\ff\fa\eb\e5\fe\a7\ec\fb\fc\f4\a6\e4\ea\f0\ae\e3")
+ (table $0 0 funcref)
+ (global $global$ (mut eqref) (ref.null eq))
+ (global $global$_0 (mut externref) (ref.null extern))
+ (global $global$_1 (mut v128) (v128.const i32x4 0xfffffff9 0x06071c48 0x3f800000 0xc3800ae1))
+ (global $global$_2 (mut eqref) (ref.null eq))
+ (global $global$_3 (mut f64) (f64.const 0))
+ (global $hangLimit (mut i32) (i32.const 10))
+ (event $event$ (attr 0) (param i64 i32))
+ (export "hashMemory" (func $hashMemory))
+ (export "memory" (memory $0))
+ (export "hangLimitInitializer" (func $hangLimitInitializer))
+ (func $hashMemory (result i32)
+  (local $0 i32)
+  (block
+   (if
+    (i32.eqz
+     (global.get $hangLimit)
+    )
+    (return
+     (i32.const 64)
+    )
+   )
+   (global.set $hangLimit
+    (i32.sub
+     (global.get $hangLimit)
+     (i32.const 1)
+    )
+   )
+  )
+  (block (result i32)
+   (local.set $0
+    (i32.const 5381)
+   )
+   (local.set $0
+    (i32.const 1140933654)
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 5)
+      )
+      (i32.const -127)
+     )
+     (i32.load8_u offset=1
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (i32.const 303045650)
+       (i32.const 5)
+      )
+      (i32.shl
+       (ref.eq
+        (i31.new
+         (i32.const -65535)
+        )
+        (tuple.extract 2
+         (tuple.make
+          (f64.const 274877906944)
+          (i31.new
+           (i32.const -134217728)
+          )
+          (ref.null eq)
+         )
+        )
+       )
+       (i32.const 5)
+      )
+     )
+     (i32.load8_u offset=2
+      (i32.const 0)
+     )
+    )
+   )
+   (nop)
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (loop $label$1 (result i32)
+       (block
+        (if
+         (i32.eqz
+          (global.get $hangLimit)
+         )
+         (return
+          (i32.const 4878)
+         )
+        )
+        (global.set $hangLimit
+         (i32.sub
+          (global.get $hangLimit)
+          (i32.const 1)
+         )
+        )
+       )
+       (block $label$2 (result i32)
+        (drop
+         (f64.const 3402823466385288598117041e14)
+        )
+        (loop $label$6
+         (block
+          (if
+           (i32.eqz
+            (global.get $hangLimit)
+           )
+           (return
+            (i32.const -13)
+           )
+          )
+          (global.set $hangLimit
+           (i32.sub
+            (global.get $hangLimit)
+            (i32.const 1)
+           )
+          )
+         )
+         (block
+          (block $label$7
+           (nop)
+           (if
+            (block $label$8
+             (nop)
+             (br $label$1)
+            )
+            (block $label$9
+             (f64.store offset=2 align=2
+              (i32.and
+               (i32.const 118163717)
+               (i32.const 15)
+              )
+              (if (result f64)
+               (call $hashMemory)
+               (block $label$10 (result f64)
+                (memory.copy
+                 (i32.const -129)
+                 (i32.and
+                  (i32.const 1195786829)
+                  (i32.const 15)
+                 )
+                 (i32.const -8)
+                )
+                (f64.const -562949953421312.2)
+               )
+               (block $label$11
+                (nop)
+                (br $label$7)
+               )
+              )
+             )
+             (if
+              (i32.eqz
+               (i32.atomic.load
+                (i32.and
+                 (i32.const 65535)
+                 (i32.const 15)
+                )
+               )
+              )
+              (block $label$12
+               (nop)
+               (nop)
+              )
+              (block $label$13
+               (br_if $label$7
+                (i32.const 10539)
+               )
+               (loop $label$14
+                (block
+                 (if
+                  (i32.eqz
+                   (global.get $hangLimit)
+                  )
+                  (return
+                   (i32.const 1495078923)
+                  )
+                 )
+                 (global.set $hangLimit
+                  (i32.sub
+                   (global.get $hangLimit)
+                   (i32.const 1)
+                  )
+                 )
+                )
+                (atomic.fence)
+               )
+              )
+             )
+            )
+            (nop)
+           )
+          )
+          (br_if $label$6
+           (i32.const -50)
+          )
+          (loop $label$15
+           (block
+            (if
+             (i32.eqz
+              (global.get $hangLimit)
+             )
+             (return
+              (i32.const -96)
+             )
+            )
+            (global.set $hangLimit
+             (i32.sub
+              (global.get $hangLimit)
+              (i32.const 1)
+             )
+            )
+           )
+           (block $label$16
+            (if
+             (i32.eqz
+              (br_if $label$2
+               (i8x16.extract_lane_s 2
+                (f64x2.gt
+                 (v128.const i32x4 0xffffffc0 0xffffffff 0x60631d62 0x630f6218)
+                 (if (result v128)
+                  (i32.eqz
+                   (f32.ne
+                    (block $label$18
+                     (nop)
+                     (br $label$15)
+                    )
+                    (f32.const -nan:0x7fff8a)
+                   )
+                  )
+                  (block $label$19 (result v128)
+                   (nop)
+                   (v128.const i32x4 0x00000000 0x38100000 0x00000000 0x40d89880)
+                  )
+                  (block $label$20
+                   (if
+                    (i32.atomic.rmw8.cmpxchg_u offset=4
+                     (i32.and
+                      (i32.const 2)
+                      (i32.const 15)
+                     )
+                     (i32.const 65525)
+                     (br_if $label$2
+                      (i32.const -33554432)
+                      (i64.lt_u
+                       (i64.const -65536)
+                       (i64.const 6663)
+                      )
+                     )
+                    )
+                    (block $label$21
+                     (br_if $label$21
+                      (i32.eqz
+                       (i32.const 65535)
+                      )
+                     )
+                     (nop)
+                    )
+                    (block $label$22
+                     (v128.store offset=4
+                      (i32.and
+                       (i32.const 55)
+                       (i32.const 15)
+                      )
+                      (v128.const i32x4 0xfffffe00 0x7fffffff 0x00005b34 0x00000039)
+                     )
+                     (nop)
+                    )
+                   )
+                   (br $label$16)
+                  )
+                 )
+                )
+               )
+               (i32.eqz
+                (i32.const 85459227)
+               )
+              )
+             )
+             (block $label$23
+              (block $label$24
+               (block $label$25
+                (nop)
+                (nop)
+               )
+               (nop)
+              )
+              (nop)
+             )
+             (block $label$26
+              (if
+               (br_if $label$2
+                (i32.const 1091126348)
+                (i32.const 1276841216)
+               )
+               (br_if $label$26
+                (i32.eqz
+                 (tuple.extract 0
+                  (if (result i32 v128 f64 v128)
+                   (i32.load8_u offset=3
+                    (i32.and
+                     (f64.ge
+                      (block $label$27 (result f64)
+                       (nop)
+                       (f64.const 41)
+                      )
+                      (f64x2.extract_lane 0
+                       (v128.const i32x4 0xffffc000 0x00000007 0x00000001 0x473f2147)
+                      )
+                     )
+                     (i32.const 15)
+                    )
+                   )
+                   (block $label$28 (result i32 v128 f64 v128)
+                    (tuple.make
+                     (i32.const 67308125)
+                     (v128.const i32x4 0xff00011d 0x0601e545 0x7f0e14ff 0x00b1f843)
+                     (f64.const 1314148947)
+                     (v128.const i32x4 0x0000003a 0x42d00000 0x00000000 0x40280000)
+                    )
+                   )
+                   (block $label$29 (result i32 v128 f64 v128)
+                    (br_if $label$15
+                     (i32.eqz
+                      (br_if $label$2
+                       (i32.const -8192)
+                       (i32.eqz
+                        (i32.const -2)
+                       )
+                      )
+                     )
+                    )
+                    (tuple.make
+                     (i32.const 65534)
+                     (v128.const i32x4 0x41530000 0x008045b2 0x01ff7f00 0xff2d8349)
+                     (f64.const 1797693134862315708145274e284)
+                     (v128.const i32x4 0xffbc630d 0xffb6ffbb 0x00015658 0xffb4ffff)
+                    )
+                   )
+                  )
+                 )
+                )
+               )
+               (block $label$30
+                (if
+                 (loop $label$31 (result i32)
+                  (block
+                   (if
+                    (i32.eqz
+                     (global.get $hangLimit)
+                    )
+                    (return
+                     (i32.const 1578633994)
+                    )
+                   )
+                   (global.set $hangLimit
+                    (i32.sub
+                     (global.get $hangLimit)
+                     (i32.const 1)
+                    )
+                   )
+                  )
+                  (block $label$32 (result i32)
+                   (block $label$33
+                    (if
+                     (i32.eqz
+                      (i32.atomic.rmw.and offset=4
+                       (i32.const -2147483648)
+                       (block $label$34
+                        (loop $label$35
+                         (block
+                          (if
+                           (i32.eqz
+                            (global.get $hangLimit)
+                           )
+                           (return
+                            (i32.const 403574365)
+                           )
+                          )
+                          (global.set $hangLimit
+                           (i32.sub
+                            (global.get $hangLimit)
+                            (i32.const 1)
+                           )
+                          )
+                         )
+                         (block
+                          (nop)
+                          (br_if $label$35
+                           (i32.const -65536)
+                          )
+                          (nop)
+                         )
+                        )
+                        (br $label$1)
+                       )
+                      )
+                     )
+                     (block $label$36
+                      (nop)
+                      (br_if $label$16
+                       (i32.const 2136)
+                      )
+                     )
+                     (block $label$37
+                      (nop)
+                      (nop)
+                     )
+                    )
+                    (atomic.fence)
+                   )
+                   (f32.lt
+                    (f32.const 2147483648)
+                    (f32.const 2147483648)
+                   )
+                  )
+                 )
+                 (block $label$40
+                  (i32.atomic.store16 offset=2
+                   (i32.and
+                    (i31.get_s
+                     (loop $label$41
+                      (block
+                       (if
+                        (i32.eqz
+                         (global.get $hangLimit)
+                        )
+                        (return
+                         (i32.const -2)
+                        )
+                       )
+                       (global.set $hangLimit
+                        (i32.sub
+                         (global.get $hangLimit)
+                         (i32.const 1)
+                        )
+                       )
+                      )
+                      (block $label$42
+                       (loop $label$43
+                        (block
+                         (if
+                          (i32.eqz
+                           (global.get $hangLimit)
+                          )
+                          (return
+                           (i32.const -13)
+                          )
+                         )
+                         (global.set $hangLimit
+                          (i32.sub
+                           (global.get $hangLimit)
+                           (i32.const 1)
+                          )
+                         )
+                        )
+                        (block $label$44
+                         (nop)
+                         (nop)
+                        )
+                       )
+                       (block $label$45
+                        (nop)
+                        (br $label$16)
+                       )
+                      )
+                     )
+                    )
+                    (i32.const 15)
+                   )
+                   (block $label$46
+                    (nop)
+                    (ref.is_null
+                     (if
+                      (i32.eqz
+                       (if (result i32)
+                        (i32.eqz
+                         (block $label$47
+                          (nop)
+                          (br $label$16)
+                         )
+                        )
+                        (i32.const -4194304)
+                        (i32.const 5140)
+                       )
+                      )
+                      (block $label$48
+                       (block $label$49
+                        (nop)
+                        (br_if $label$15
+                         (i32.eqz
+                          (loop $label$50 (result i32)
+                           (block
+                            (if
+                             (i32.eqz
+                              (global.get $hangLimit)
+                             )
+                             (return
+                              (i32.const 112)
+                             )
+                            )
+                            (global.set $hangLimit
+                             (i32.sub
+                              (global.get $hangLimit)
+                              (i32.const 1)
+                             )
+                            )
+                           )
+                           (block (result i32)
+                            (nop)
+                            (br_if $label$50
+                             (i32.eqz
+                              (i32.const 3)
+                             )
+                            )
+                            (i31.get_s
+                             (i31.new
+                              (i32.const 4095)
+                             )
+                            )
+                           )
+                          )
+                         )
+                        )
+                       )
+                       (br $label$40)
+                      )
+                      (block $label$51
+                       (drop
+                        (ref.null exn)
+                       )
+                       (br $label$16)
+                      )
+                     )
+                    )
+                   )
+                  )
+                 )
+                 (block $label$52
+                  (loop $label$53
+                   (block
+                    (if
+                     (i32.eqz
+                      (global.get $hangLimit)
+                     )
+                     (return
+                      (i32.const 7506)
+                     )
+                    )
+                    (global.set $hangLimit
+                     (i32.sub
+                      (global.get $hangLimit)
+                      (i32.const 1)
+                     )
+                    )
+                   )
+                   (block
+                    (nop)
+                    (br_if $label$53
+                     (loop $label$54 (result i32)
+                      (block
+                       (if
+                        (i32.eqz
+                         (global.get $hangLimit)
+                        )
+                        (return
+                         (i32.const 50922251)
+                        )
+                       )
+                       (global.set $hangLimit
+                        (i32.sub
+                         (global.get $hangLimit)
+                         (i32.const 1)
+                        )
+                       )
+                      )
+                      (i32.const 6912)
+                     )
+                    )
+                    (br_if $label$6
+                     (br_if $label$2
+                      (call $hashMemory)
+                      (loop $label$55 (result i32)
+                       (block
+                        (if
+                         (i32.eqz
+                          (global.get $hangLimit)
+                         )
+                         (return
+                          (i32.const 319820056)
+                         )
+                        )
+                        (global.set $hangLimit
+                         (i32.sub
+                          (global.get $hangLimit)
+                          (i32.const 1)
+                         )
+                        )
+                       )
+                       (i32.const 2147483647)
+                      )
+                     )
+                    )
+                   )
+                  )
+                  (memory.copy
+                   (i32.and
+                    (i32.atomic.load offset=3
+                     (i32.and
+                      (loop $label$56 (result i32)
+                       (block
+                        (if
+                         (i32.eqz
+                          (global.get $hangLimit)
+                         )
+                         (return
+                          (i32.const -2147483648)
+                         )
+                        )
+                        (global.set $hangLimit
+                         (i32.sub
+                          (global.get $hangLimit)
+                          (i32.const 1)
+                         )
+                        )
+                       )
+                       (loop $label$57 (result i32)
+                        (block
+                         (if
+                          (i32.eqz
+                           (global.get $hangLimit)
+                          )
+                          (return
+                           (i32.const 262143)
+                          )
+                         )
+                         (global.set $hangLimit
+                          (i32.sub
+                           (global.get $hangLimit)
+                           (i32.const 1)
+                          )
+                         )
+                        )
+                        (block (result i32)
+                         (block $label$58
+                          (if
+                           (i32.eqz
+                            (i32.const 775321902)
+                           )
+                           (nop)
+                           (if
+                            (i32.eqz
+                             (i32.const -18)
+                            )
+                            (nop)
+                            (nop)
+                           )
+                          )
+                          (nop)
+                         )
+                         (br_if $label$57
+                          (i32.const 4194304)
+                         )
+                         (f32.le
+                          (f32.const 18446744073709551615)
+                          (f32.const -nan:0x7fff87)
+                         )
+                        )
+                       )
+                      )
+                      (i32.const 15)
+                     )
+                    )
+                    (i32.const 15)
+                   )
+                   (i32.and
+                    (block $label$59 (result i32)
+                     (loop $label$60
+                      (block
+                       (if
+                        (i32.eqz
+                         (global.get $hangLimit)
+                        )
+                        (return
+                         (i32.const -32768)
+                        )
+                       )
+                       (global.set $hangLimit
+                        (i32.sub
+                         (global.get $hangLimit)
+                         (i32.const 1)
+                        )
+                       )
+                      )
+                      (block
+                       (block $label$61
+                        (drop
+                         (i31.new
+                          (i32.const -8192)
+                         )
+                        )
+                        (nop)
+                       )
+                       (br_if $label$60
+                        (i32.eqz
+                         (loop $label$62 (result i32)
+                          (block
+                           (if
+                            (i32.eqz
+                             (global.get $hangLimit)
+                            )
+                            (return
+                             (i32.const 7)
+                            )
+                           )
+                           (global.set $hangLimit
+                            (i32.sub
+                             (global.get $hangLimit)
+                             (i32.const 1)
+                            )
+                           )
+                          )
+                          (block $label$63 (result i32)
+                           (nop)
+                           (i32.const 65521)
+                          )
+                         )
+                        )
+                       )
+                       (memory.fill
+                        (i32.trunc_f32_u
+                         (f32.const 256)
+                        )
+                        (i64.eq
+                         (i64.const 256)
+                         (i64.const -16384)
+                        )
+                        (i32.const 387455770)
+                       )
+                      )
+                     )
+                     (i32.const 4627)
+                    )
+                    (i32.const 15)
+                   )
+                   (i32.load8_s offset=3
+                    (i32.and
+                     (br_if $label$2
+                      (loop $label$64 (result i32)
+                       (block
+                        (if
+                         (i32.eqz
+                          (global.get $hangLimit)
+                         )
+                         (return
+                          (i32.const -96)
+                         )
+                        )
+                        (global.set $hangLimit
+                         (i32.sub
+                          (global.get $hangLimit)
+                          (i32.const 1)
+                         )
+                        )
+                       )
+                       (block (result i32)
+                        (block $label$65
+                         (loop $label$66
+                          (block
+                           (if
+                            (i32.eqz
+                             (global.get $hangLimit)
+                            )
+                            (return
+                             (i32.const 65518)
+                            )
+                           )
+                           (global.set $hangLimit
+                            (i32.sub
+                             (global.get $hangLimit)
+                             (i32.const 1)
+                            )
+                           )
+                          )
+                          (nop)
+                         )
+                         (nop)
+                        )
+                        (br_if $label$64
+                         (tuple.extract 1
+                          (tuple.make
+                           (v128.const i32x4 0x0606ff82 0xfffe0000 0x04052000 0xfffe0000)
+                           (i32.const 1529028702)
+                          )
+                         )
+                        )
+                        (loop $label$67 (result i32)
+                         (block
+                          (if
+                           (i32.eqz
+                            (global.get $hangLimit)
+                           )
+                           (return
+                            (i32.const -1073741825)
+                           )
+                          )
+                          (global.set $hangLimit
+                           (i32.sub
+                            (global.get $hangLimit)
+                            (i32.const 1)
+                           )
+                          )
+                         )
+                         (i32.const 128)
+                        )
+                       )
+                      )
+                      (i32.eqz
+                       (ref.is_null
+                        (select (result anyref)
+                         (ref.null eq)
+                         (ref.null extern)
+                         (i32.const 129)
+                        )
+                       )
+                      )
+                     )
+                     (i32.const 15)
+                    )
+                   )
+                  )
+                 )
+                )
+                (nop)
+               )
+              )
+              (block $label$68
+               (nop)
+               (nop)
+              )
+             )
+            )
+            (nop)
+           )
+          )
+         )
+        )
+        (if (result i32)
+         (block $label$69 (result i32)
+          (if
+           (if (result i32)
+            (br_if $label$2
+             (loop $label$71 (result i32)
+              (block
+               (if
+                (i32.eqz
+                 (global.get $hangLimit)
+                )
+                (return
+                 (i32.const 15)
+                )
+               )
+               (global.set $hangLimit
+                (i32.sub
+                 (global.get $hangLimit)
+                 (i32.const 1)
+                )
+               )
+              )
+              (block (result i32)
+               (block $label$72
+                (br_if $label$72
+                 (i32.const -1)
+                )
+                (nop)
+               )
+               (br_if $label$71
+                (i32.eqz
+                 (i32.const -2147483648)
+                )
+               )
+               (if (result i32)
+                (i32.eqz
+                 (i32.const -32766)
+                )
+                (block $label$73 (result i32)
+                 (br_if $label$71
+                  (i32.eqz
+                   (tuple.extract 1
+                    (block $label$74
+                     (nop)
+                     (br $label$1)
+                    )
+                   )
+                  )
+                 )
+                 (ref.is_null
+                  (global.get $global$_0)
+                 )
+                )
+                (i32x4.all_true
+                 (v128.const i32x4 0x3c800c01 0x193fff27 0x52a20001 0x970000ff)
+                )
+               )
+              )
+             )
+             (i32.eqz
+              (loop $label$70 (result i32)
+               (block
+                (if
+                 (i32.eqz
+                  (global.get $hangLimit)
+                 )
+                 (return
+                  (i32.const 1048576)
+                 )
+                )
+                (global.set $hangLimit
+                 (i32.sub
+                  (global.get $hangLimit)
+                  (i32.const 1)
+                 )
+                )
+               )
+               (i32.const 256)
+              )
+             )
+            )
+            (i32.atomic.load8_u offset=22
+             (i32.const 858607703)
+            )
+            (block $label$75 (result i32)
+             (nop)
+             (br_if $label$75
+              (i32.const 7)
+              (i31.get_s
+               (tuple.extract 0
+                (tuple.make
+                 (i31.new
+                  (i32.const 219815443)
+                 )
+                 (v128.const i32x4 0x00000001 0x151b1e13 0x00000001 0x1a5f0000)
+                )
+               )
+              )
+             )
+            )
+           )
+           (block $label$76
+            (nop)
+           )
+           (nop)
+          )
+          (i32.const 2097152)
+         )
+         (i32.const -84)
+         (block $label$77 (result i32)
+          (i32.const -16)
+         )
+        )
+       )
+      )
+      (local.get $0)
+     )
+     (i32.load8_u offset=4
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 5)
+      )
+      (local.get $0)
+     )
+     (i32.load8_u offset=5
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 5)
+      )
+      (local.get $0)
+     )
+     (i32.const 6506)
+    )
+   )
+   (nop)
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 5)
+      )
+      (local.get $0)
+     )
+     (i32.load8_u offset=6
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (i32.const 1633371484)
+       (i32.const 5)
+      )
+      (i32.xor
+       (i32.add
+        (i32.shl
+         (local.get $0)
+         (i32.const 5)
+        )
+        (local.get $0)
+       )
+       (i32.load8_u offset=8
+        (i32.const 0)
+       )
+      )
+     )
+     (i32.load8_u offset=9
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 5)
+      )
+      (local.get $0)
+     )
+     (i32.load8_u offset=10
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.const 1937132399)
+     (i32.load8_u offset=11
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (i32.const -85)
+       (i32.const 5)
+      )
+      (local.get $0)
+     )
+     (i32.shl
+      (local.get $0)
+      (i32.const 5)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 5)
+      )
+      (local.get $0)
+     )
+     (i32.load8_u offset=13
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.const 5)
+      (local.get $0)
+     )
+     (i32.load8_u offset=14
+      (i32.const 0)
+     )
+    )
+   )
+   (local.set $0
+    (i32.xor
+     (i32.add
+      (i32.shl
+       (local.get $0)
+       (i32.const 5)
+      )
+      (local.get $0)
+     )
+     (i32.load8_u offset=12
+      (i32.const 0)
+     )
+    )
+   )
+   (local.get $0)
   )
  )
  (func $hangLimitInitializer
diff --git a/binaryen/test/passes/translate-to-fuzz_all-features.wast b/binaryen/test/passes/translate-to-fuzz_all-features.wast
deleted file mode 100644
--- a/binaryen/test/passes/translate-to-fuzz_all-features.wast
+++ /dev/null
@@ -1,101 +0,0 @@
-(module # fake module here, for test harness, but it is really not needed
-..
-any
-3INPUT
-h e r e
-*will*
-d0
-0.753538467597066
-2.2339337309978227
-.................
-lorem ipsum whatever
-
-through the darkness of future past
-the magician longs to see
-one [chants|chance] out between two worlds
-fire, walk with me
-
-
-h e r e
-*will*
-d0
-0.753538467597066
-2.2339337309978227
-.................
-lorem ipsum whatever
-
-through the darkness of future past
-the magician longs to see
-one [chants|chance] out between two worlds
-fire, walk with me
-
-
-(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
-
-MOAR testing09237861235980723894570389yfskdjhgfm13jo847rtnjcsjjdhfgnc12o387456vb1p98364vlaisutfvlKUYASDOV*&Q@$%VOUAYFROVLUKSYDFP(*A^*&%DFASF________
-<>?><?><?><>?>>?<>??><A?S>D<?A>S<D?><G?S><DG?S><G
-
-2.2339337309978227
-.................
-lorem ipsum whatever
-
-through the darkness of future past
-the magician longs to see
-one [chants|chance] out between two worlds
-fire, walk with me
-
-
-(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
-
-MOAR testing09237861235980723894570389yfskdjhgfm13jo847rtnjcsjjdhfgnc12o387456vb1p98364vlaisutfvlKUYASDOV*&Q@$%VOUAYFROVLUKSYDFP(*A^*&%DFASF________
-<>?><?><?><>?>>?<>??><A?S>D<?A>S<D?><G?S><DG?S><G
-
-INPUT
-h e r e
-*will*
-d0
-0.753538467597066
-2.2339337309978227
-.................
-lorem ipsum whatever
-
-through the darkness of future past
-the magician longs to see
-one [chants|chance] out between two worlds
-fire, walk with me
-
-
-h e r e
-*will*
-d0
-0.753538467597066
-2.2339337309978227
-.................
-lorem ipsum whatever
-
-through the darkness of future past
-the magician longs to see
-one [chants|chance] out between two worlds
-fire, walk with me
-
-
-(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
-
-MOAR testing09237861235980723894570389yfskdjhgfm13jo847rtnjcsjjdhfgnc12o387456vb1p98364vlaisutfvlKUYASDOV*&Q@$%VOUAYFROVLUKSYDFP(*A^*&%DFASF________
-<>?><?><?><>?>>?<>??><A?S>D<?A>S<D?><G?S><DG?S><G
-
-2.2339337309978227
-.................
-lorem ipsum whatever
-
-through the darkness of future past
-the magician longs to see
-one [chants|chance] out between two worlds
-fire, walk with me
-
-
-(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
-
-) # this isn't really needed either
-
-bleh
diff --git a/binaryen/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/binaryen/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
@@ -0,0 +1,42 @@
+total
+ [events]       : 1       
+ [exports]      : 3       
+ [funcs]        : 2       
+ [globals]      : 6       
+ [imports]      : 6       
+ [memory-data]  : 22      
+ [table-data]   : 0       
+ [total]        : 592     
+ [vars]         : 1       
+ atomic.cmpxchg : 1       
+ atomic.fence   : 3       
+ binary         : 58      
+ block          : 84      
+ break          : 26      
+ call           : 4       
+ call_ref       : 1       
+ const          : 149     
+ data.drop      : 1       
+ drop           : 3       
+ global.get     : 29      
+ global.set     : 17      
+ i31.get        : 2       
+ i31.new        : 7       
+ if             : 35      
+ load           : 15      
+ local.get      : 10      
+ local.set      : 14      
+ loop           : 13      
+ memory.init    : 1       
+ nop            : 36      
+ ref.eq         : 2       
+ ref.func       : 2       
+ ref.is_null    : 3       
+ ref.null       : 8       
+ return         : 14      
+ select         : 2       
+ simd_extract   : 2       
+ store          : 8       
+ tuple.extract  : 5       
+ tuple.make     : 4       
+ unary          : 33      
diff --git a/binaryen/test/passes/translate-to-fuzz_all-features_metrics_noprint.wast b/binaryen/test/passes/translate-to-fuzz_all-features_metrics_noprint.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/passes/translate-to-fuzz_all-features_metrics_noprint.wast
@@ -0,0 +1,101 @@
+(module # fake module here, for test harness, but it is really not needed
+..
+any
+3INPUT
+h e r e
+*will*
+d0
+0.753538467597066
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+h e r e
+*will*
+d0
+0.753538467597066
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
+
+MOAR testing09237861235980723894570389yfskdjhgfm13jo847rtnjcsjjdhfgnc12o387456vb1p98364vlaisutfvlKUYASDOV*&Q@$%VOUAYFROVLUKSYDFP(*A^*&%DFASF________
+<>?><?><?><>?>>?<>??><A?S>D<?A>S<D?><G?S><DG?S><G
+
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
+
+MOAR testing09237861235980723894570389yfskdjhgfm13jo847rtnjcsjjdhfgnc12o387456vb1p98364vlaisutfvlKUYASDOV*&Q@$%VOUAYFROVLUKSYDFP(*A^*&%DFASF________
+<>?><?><?><>?>>?<>??><A?S>D<?A>S<D?><G?S><DG?S><G
+
+INPUT
+h e r e
+*will*
+d0
+0.753538467597066
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+h e r e
+*will*
+d0
+0.753538467597066
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
+
+MOAR testing09237861235980723894570389yfskdjhgfm13jo847rtnjcsjjdhfgnc12o387456vb1p98364vlaisutfvlKUYASDOV*&Q@$%VOUAYFROVLUKSYDFP(*A^*&%DFASF________
+<>?><?><?><>?>>?<>??><A?S>D<?A>S<D?><G?S><DG?S><G
+
+2.2339337309978227
+.................
+lorem ipsum whatever
+
+through the darkness of future past
+the magician longs to see
+one [chants|chance] out between two worlds
+fire, walk with me
+
+
+(&!*^@$*&@!^*&@#^$*&@#$*&@#$^*&@^#$)(&)(!&$(*&^@&#*$
+
+) # this isn't really needed either
+
+bleh
diff --git a/binaryen/test/passes/vacuum_all-features.txt b/binaryen/test/passes/vacuum_all-features.txt
--- a/binaryen/test/passes/vacuum_all-features.txt
+++ b/binaryen/test/passes/vacuum_all-features.txt
@@ -261,12 +261,6 @@
  )
  (func $unary-binary-may-trap
   (drop
-   (i64.div_s
-    (i64.const -1)
-    (i64.const 729618461987467893)
-   )
-  )
-  (drop
    (i64.trunc_f32_u
     (f32.const 70847791997969805621592064)
    )
diff --git a/binaryen/test/print/min.minified.txt b/binaryen/test/print/min.minified.txt
--- a/binaryen/test/print/min.minified.txt
+++ b/binaryen/test/print/min.minified.txt
@@ -1,4 +1,4 @@
-(module(type $i32_=>_i32 (func(param i32)(result i32)))(type $i32_i32_i32_=>_i32 (func(param i32 i32 i32)(result i32)))(type $i32_i32_=>_f32 (func(param i32 i32)(result f32)))(type $f32_=>_f32 (func(param f32)(result f32)))(memory $0 256 256)
+(module(type $i32_=>_i32 (func(param i32)(result i32)))(type $i32_i32_i32_=>_i32 (func(param i32 i32 i32)(result i32)))(type $f32_=>_f32 (func(param f32)(result f32)))(type $i32_i32_=>_f32 (func(param i32 i32)(result f32)))(memory $0 256 256)
 (export "floats" (func $floats))(func $floats(param $f f32)(result f32)(local $t f32)(f32.add(local.get $t)(local.get $f)))(func $neg(param $k i32)(param $p i32)(result f32)(local $n f32)(local.tee $n(f32.neg(block $block0 (result f32)(i32.store(local.get $k)(local.get $p))(f32.load(local.get $k))))))(func $littleswitch(param $x i32)(result i32)(block $topmost (result i32)(block $switch-case$2(block $switch-case$1(br_table $switch-case$1 $switch-case$2 $switch-case$1(i32.sub(local.get $x)(i32.const 1))))
 (br $topmost(i32.const 1)))
 (br $topmost(i32.const 2))(i32.const 0)))(func $f1(param $i1 i32)(param $i2 i32)(param $i3 i32)(result i32)(block $topmost (result i32)(local.get $i3))))
diff --git a/binaryen/test/print/min.txt b/binaryen/test/print/min.txt
--- a/binaryen/test/print/min.txt
+++ b/binaryen/test/print/min.txt
@@ -1,8 +1,8 @@
 (module
  (type $i32_=>_i32 (func (param i32) (result i32)))
  (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32)))
- (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
  (type $f32_=>_f32 (func (param f32) (result f32)))
+ (type $i32_i32_=>_f32 (func (param i32 i32) (result f32)))
  (memory $0 256 256)
  (export "floats" (func $floats))
  (func $floats (param $f f32) (result f32)
diff --git a/binaryen/test/reference-types.wast.fromBinary.noDebugInfo b/binaryen/test/reference-types.wast.fromBinary.noDebugInfo
--- a/binaryen/test/reference-types.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/reference-types.wast.fromBinary.noDebugInfo
@@ -9,7 +9,7 @@
  (type $none_=>_exnref (func (result exnref)))
  (type $none_=>_none (func))
  (type $externref_=>_funcref (func (param externref) (result funcref)))
- (import "env" "import_global" (global $gimport$1 externref))
+ (import "env" "import_global" (global $gimport$0 externref))
  (import "env" "import_func" (func $fimport$0 (param externref) (result funcref)))
  (table $0 4 4 funcref)
  (elem (i32.const 0) $0 $1 $2 $3)
@@ -23,7 +23,7 @@
  (global $global$7 (mut anyref) (ref.func $4))
  (global $global$8 (mut anyref) (ref.null exn))
  (export "export_func" (func $fimport$0))
- (export "export_global" (global $gimport$1))
+ (export "export_global" (global $gimport$0))
  (func $0 (param $0 externref)
   (nop)
  )
diff --git a/binaryen/test/simd.wast b/binaryen/test/simd.wast
--- a/binaryen/test/simd.wast
+++ b/binaryen/test/simd.wast
@@ -316,6 +316,12 @@
    (local.get $1)
   )
  )
+ (func $i64x2.eq (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
  (func $f32x4.eq (param $0 v128) (param $1 v128) (result v128)
   (f32x4.eq
    (local.get $0)
@@ -424,6 +430,123 @@
    (local.get $2)
   )
  )
+ (func $v8x16.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v8x16.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v16x8.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v16x8.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v32x4.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v32x4.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v64x2.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v64x2.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v128.load8_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load8_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load16_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load16_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load32_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load32_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane_align (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane_offset (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane_align_offset (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane align=1 offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store8_lane (param $0 i32) (param $1 v128)
+  (v128.store8_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store16_lane (param $0 i32) (param $1 v128)
+  (v128.store16_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store32_lane (param $0 i32) (param $1 v128)
+  (v128.store32_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane (param $0 i32) (param $1 v128)
+  (v128.store64_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane_align (param $0 i32) (param $1 v128)
+  (v128.store64_lane align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane_offset (param $0 i32) (param $1 v128)
+  (v128.store64_lane offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane_align_offset (param $0 i32) (param $1 v128)
+  (v128.store64_lane align=1 offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.popcnt (param $0 v128) (result v128)
+  (i8x16.popcnt
+   (local.get $0)
+  )
+ )
  (func $i8x16.abs (param $0 v128) (result v128)
   (i8x16.abs
    (local.get $0)
@@ -654,6 +777,36 @@
    (local.get $1)
   )
  )
+ (func $i16x8.q15mulr_sat_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.q15mulr_sat_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_low_i8x16_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_low_i8x16_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_high_i8x16_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_high_i8x16_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_low_i8x16_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_low_i8x16_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_high_i8x16_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_high_i8x16_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
  (func $i32x4.abs (param $0 v128) (result v128)
   (i32x4.abs
    (local.get $0)
@@ -745,21 +898,40 @@
    (local.get $1)
   )
  )
- (func $i64x2.neg (param $0 v128) (result v128)
-  (i64x2.neg
+ (func $i32x4.extmul_low_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_low_i16x8_s
    (local.get $0)
+   (local.get $1)
   )
  )
- (func $i64x2.any_true (param $0 v128) (result i32)
-  (i64x2.any_true
+ (func $i32x4.extmul_high_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_high_i16x8_s
    (local.get $0)
+   (local.get $1)
   )
  )
- (func $i64x2.all_true (param $0 v128) (result i32)
-  (i64x2.all_true
+ (func $i32x4.extmul_low_i16x8_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_low_i16x8_u
    (local.get $0)
+   (local.get $1)
   )
  )
+ (func $i32x4.extmul_high_i16x8_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_high_i16x8_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.neg (param $0 v128) (result v128)
+  (i64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $i64x2.bitmask (param $0 v128) (result i32)
+  (i64x2.bitmask
+   (local.get $0)
+  )
+ )
  (func $i64x2.shl (param $0 v128) (param $1 i32) (result v128)
   (i64x2.shl
    (local.get $0)
@@ -796,6 +968,30 @@
    (local.get $1)
   )
  )
+ (func $i64x2.extmul_low_i32x4_s (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_low_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extmul_high_i32x4_s (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_high_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extmul_low_i32x4_u (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_low_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extmul_high_i32x4_u (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_high_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
  (func $f32x4.add (param $0 v128) (param $1 v128) (result v128)
   (f32x4.add
    (local.get $0)
@@ -990,6 +1186,26 @@
    (local.get $2)
   )
  )
+ (func $i16x8.extadd_pairwise_i8x16_s (param $0 v128) (result v128)
+  (i16x8.extadd_pairwise_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $i16x8.extadd_pairwise_i8x16_u (param $0 v128) (result v128)
+  (i16x8.extadd_pairwise_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $i32x4.extadd_pairwise_i16x8_s (param $0 v128) (result v128)
+  (i32x4.extadd_pairwise_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.extadd_pairwise_i16x8_u (param $0 v128) (result v128)
+  (i32x4.extadd_pairwise_i16x8_u
+   (local.get $0)
+  )
+ )
  (func $i32x4.trunc_sat_f32x4_s (param $0 v128) (result v128)
   (i32x4.trunc_sat_f32x4_s
    (local.get $0)
@@ -1114,6 +1330,26 @@
    (local.get $0)
   )
  )
+ (func $i64x2.widen_low_i32x4_s (param $0 v128) (result v128)
+  (i64x2.widen_low_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.widen_high_i32x4_s (param $0 v128) (result v128)
+  (i64x2.widen_high_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.widen_low_i32x4_u (param $0 v128) (result v128)
+  (i64x2.widen_low_i32x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.widen_high_i32x4_u (param $0 v128) (result v128)
+  (i64x2.widen_high_i32x4_u
+   (local.get $0)
+  )
+ )
  (func $i16x8.load8x8_u (param $0 i32) (result v128)
   (i16x8.load8x8_u
    (local.get $0)
@@ -1158,6 +1394,16 @@
   (v8x16.swizzle
    (local.get $0)
    (local.get $1)
+  )
+ )
+ (func $prefetch.t (param $0 i32)
+  (prefetch.t offset=3 align=2
+   (local.get $0)
+  )
+ )
+ (func $prefetch.nt (param $0 i32)
+  (prefetch.nt offset=3 align=2
+   (local.get $0)
   )
  )
 )
diff --git a/binaryen/test/simd.wast.from-wast b/binaryen/test/simd.wast.from-wast
--- a/binaryen/test/simd.wast.from-wast
+++ b/binaryen/test/simd.wast.from-wast
@@ -1,12 +1,14 @@
 (module
  (type $v128_v128_=>_v128 (func (param v128 v128) (result v128)))
  (type $v128_=>_v128 (func (param v128) (result v128)))
- (type $v128_=>_i32 (func (param v128) (result i32)))
  (type $i32_=>_v128 (func (param i32) (result v128)))
+ (type $v128_=>_i32 (func (param v128) (result i32)))
  (type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
- (type $none_=>_v128 (func (result v128)))
  (type $v128_v128_v128_=>_v128 (func (param v128 v128 v128) (result v128)))
  (type $i32_v128_=>_none (func (param i32 v128)))
+ (type $i32_v128_=>_v128 (func (param i32 v128) (result v128)))
+ (type $none_=>_v128 (func (result v128)))
+ (type $i32_=>_none (func (param i32)))
  (type $v128_=>_i64 (func (param v128) (result i64)))
  (type $v128_=>_f32 (func (param v128) (result f32)))
  (type $v128_=>_f64 (func (param v128) (result f64)))
@@ -332,6 +334,12 @@
    (local.get $1)
   )
  )
+ (func $i64x2.eq (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
  (func $f32x4.eq (param $0 v128) (param $1 v128) (result v128)
   (f32x4.eq
    (local.get $0)
@@ -440,6 +448,123 @@
    (local.get $2)
   )
  )
+ (func $v8x16.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v8x16.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v16x8.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v16x8.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v32x4.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v32x4.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v64x2.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v64x2.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v128.load8_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load8_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load16_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load16_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load32_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load32_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane_align (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane_offset (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane_align_offset (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane offset=32 align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store8_lane (param $0 i32) (param $1 v128)
+  (v128.store8_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store16_lane (param $0 i32) (param $1 v128)
+  (v128.store16_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store32_lane (param $0 i32) (param $1 v128)
+  (v128.store32_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane (param $0 i32) (param $1 v128)
+  (v128.store64_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane_align (param $0 i32) (param $1 v128)
+  (v128.store64_lane align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane_offset (param $0 i32) (param $1 v128)
+  (v128.store64_lane offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane_align_offset (param $0 i32) (param $1 v128)
+  (v128.store64_lane offset=32 align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.popcnt (param $0 v128) (result v128)
+  (i8x16.popcnt
+   (local.get $0)
+  )
+ )
  (func $i8x16.abs (param $0 v128) (result v128)
   (i8x16.abs
    (local.get $0)
@@ -670,6 +795,36 @@
    (local.get $1)
   )
  )
+ (func $i16x8.q15mulr_sat_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.q15mulr_sat_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_low_i8x16_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_low_i8x16_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_high_i8x16_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_high_i8x16_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_low_i8x16_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_low_i8x16_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_high_i8x16_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_high_i8x16_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
  (func $i32x4.abs (param $0 v128) (result v128)
   (i32x4.abs
    (local.get $0)
@@ -761,21 +916,40 @@
    (local.get $1)
   )
  )
- (func $i64x2.neg (param $0 v128) (result v128)
-  (i64x2.neg
+ (func $i32x4.extmul_low_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_low_i16x8_s
    (local.get $0)
+   (local.get $1)
   )
  )
- (func $i64x2.any_true (param $0 v128) (result i32)
-  (i64x2.any_true
+ (func $i32x4.extmul_high_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_high_i16x8_s
    (local.get $0)
+   (local.get $1)
   )
  )
- (func $i64x2.all_true (param $0 v128) (result i32)
-  (i64x2.all_true
+ (func $i32x4.extmul_low_i16x8_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_low_i16x8_u
    (local.get $0)
+   (local.get $1)
   )
  )
+ (func $i32x4.extmul_high_i16x8_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_high_i16x8_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.neg (param $0 v128) (result v128)
+  (i64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $i64x2.bitmask (param $0 v128) (result i32)
+  (i64x2.bitmask
+   (local.get $0)
+  )
+ )
  (func $i64x2.shl (param $0 v128) (param $1 i32) (result v128)
   (i64x2.shl
    (local.get $0)
@@ -812,6 +986,30 @@
    (local.get $1)
   )
  )
+ (func $i64x2.extmul_low_i32x4_s (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_low_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extmul_high_i32x4_s (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_high_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extmul_low_i32x4_u (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_low_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extmul_high_i32x4_u (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_high_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
  (func $f32x4.add (param $0 v128) (param $1 v128) (result v128)
   (f32x4.add
    (local.get $0)
@@ -1006,6 +1204,26 @@
    (local.get $2)
   )
  )
+ (func $i16x8.extadd_pairwise_i8x16_s (param $0 v128) (result v128)
+  (i16x8.extadd_pairwise_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $i16x8.extadd_pairwise_i8x16_u (param $0 v128) (result v128)
+  (i16x8.extadd_pairwise_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $i32x4.extadd_pairwise_i16x8_s (param $0 v128) (result v128)
+  (i32x4.extadd_pairwise_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.extadd_pairwise_i16x8_u (param $0 v128) (result v128)
+  (i32x4.extadd_pairwise_i16x8_u
+   (local.get $0)
+  )
+ )
  (func $i32x4.trunc_sat_f32x4_s (param $0 v128) (result v128)
   (i32x4.trunc_sat_f32x4_s
    (local.get $0)
@@ -1130,6 +1348,26 @@
    (local.get $0)
   )
  )
+ (func $i64x2.widen_low_i32x4_s (param $0 v128) (result v128)
+  (i64x2.widen_low_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.widen_high_i32x4_s (param $0 v128) (result v128)
+  (i64x2.widen_high_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.widen_low_i32x4_u (param $0 v128) (result v128)
+  (i64x2.widen_low_i32x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.widen_high_i32x4_u (param $0 v128) (result v128)
+  (i64x2.widen_high_i32x4_u
+   (local.get $0)
+  )
+ )
  (func $i16x8.load8x8_u (param $0 i32) (result v128)
   (i16x8.load8x8_u
    (local.get $0)
@@ -1174,6 +1412,16 @@
   (v8x16.swizzle
    (local.get $0)
    (local.get $1)
+  )
+ )
+ (func $prefetch.t (param $0 i32)
+  (prefetch.t offset=3 align=2
+   (local.get $0)
+  )
+ )
+ (func $prefetch.nt (param $0 i32)
+  (prefetch.nt offset=3 align=2
+   (local.get $0)
   )
  )
 )
diff --git a/binaryen/test/simd.wast.fromBinary b/binaryen/test/simd.wast.fromBinary
--- a/binaryen/test/simd.wast.fromBinary
+++ b/binaryen/test/simd.wast.fromBinary
@@ -1,12 +1,14 @@
 (module
  (type $v128_v128_=>_v128 (func (param v128 v128) (result v128)))
  (type $v128_=>_v128 (func (param v128) (result v128)))
- (type $v128_=>_i32 (func (param v128) (result i32)))
  (type $i32_=>_v128 (func (param i32) (result v128)))
+ (type $v128_=>_i32 (func (param v128) (result i32)))
  (type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
- (type $none_=>_v128 (func (result v128)))
  (type $v128_v128_v128_=>_v128 (func (param v128 v128 v128) (result v128)))
  (type $i32_v128_=>_none (func (param i32 v128)))
+ (type $i32_v128_=>_v128 (func (param i32 v128) (result v128)))
+ (type $none_=>_v128 (func (result v128)))
+ (type $i32_=>_none (func (param i32)))
  (type $v128_=>_i64 (func (param v128) (result i64)))
  (type $v128_=>_f32 (func (param v128) (result f32)))
  (type $v128_=>_f64 (func (param v128) (result f64)))
@@ -332,6 +334,12 @@
    (local.get $1)
   )
  )
+ (func $i64x2.eq (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.eq
+   (local.get $0)
+   (local.get $1)
+  )
+ )
  (func $f32x4.eq (param $0 v128) (param $1 v128) (result v128)
   (f32x4.eq
    (local.get $0)
@@ -440,6 +448,123 @@
    (local.get $2)
   )
  )
+ (func $v8x16.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v8x16.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v16x8.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v16x8.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v32x4.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v32x4.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v64x2.signselect (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v64x2.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $v128.load8_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load8_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load16_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load16_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load32_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load32_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane_align (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane_offset (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.load64_lane_align_offset (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane offset=32 align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store8_lane (param $0 i32) (param $1 v128)
+  (v128.store8_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store16_lane (param $0 i32) (param $1 v128)
+  (v128.store16_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store32_lane (param $0 i32) (param $1 v128)
+  (v128.store32_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane (param $0 i32) (param $1 v128)
+  (v128.store64_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane_align (param $0 i32) (param $1 v128)
+  (v128.store64_lane align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane_offset (param $0 i32) (param $1 v128)
+  (v128.store64_lane offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $v128.store64_lane_align_offset (param $0 i32) (param $1 v128)
+  (v128.store64_lane offset=32 align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i8x16.popcnt (param $0 v128) (result v128)
+  (i8x16.popcnt
+   (local.get $0)
+  )
+ )
  (func $i8x16.abs (param $0 v128) (result v128)
   (i8x16.abs
    (local.get $0)
@@ -670,6 +795,36 @@
    (local.get $1)
   )
  )
+ (func $i16x8.q15mulr_sat_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.q15mulr_sat_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_low_i8x16_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_low_i8x16_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_high_i8x16_s (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_high_i8x16_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_low_i8x16_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_low_i8x16_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i16x8.extmul_high_i8x16_u (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_high_i8x16_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
  (func $i32x4.abs (param $0 v128) (result v128)
   (i32x4.abs
    (local.get $0)
@@ -761,21 +916,40 @@
    (local.get $1)
   )
  )
- (func $i64x2.neg (param $0 v128) (result v128)
-  (i64x2.neg
+ (func $i32x4.extmul_low_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_low_i16x8_s
    (local.get $0)
+   (local.get $1)
   )
  )
- (func $i64x2.any_true (param $0 v128) (result i32)
-  (i64x2.any_true
+ (func $i32x4.extmul_high_i16x8_s (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_high_i16x8_s
    (local.get $0)
+   (local.get $1)
   )
  )
- (func $i64x2.all_true (param $0 v128) (result i32)
-  (i64x2.all_true
+ (func $i32x4.extmul_low_i16x8_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_low_i16x8_u
    (local.get $0)
+   (local.get $1)
   )
  )
+ (func $i32x4.extmul_high_i16x8_u (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_high_i16x8_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.neg (param $0 v128) (result v128)
+  (i64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $i64x2.bitmask (param $0 v128) (result i32)
+  (i64x2.bitmask
+   (local.get $0)
+  )
+ )
  (func $i64x2.shl (param $0 v128) (param $1 i32) (result v128)
   (i64x2.shl
    (local.get $0)
@@ -812,6 +986,30 @@
    (local.get $1)
   )
  )
+ (func $i64x2.extmul_low_i32x4_s (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_low_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extmul_high_i32x4_s (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_high_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extmul_low_i32x4_u (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_low_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $i64x2.extmul_high_i32x4_u (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_high_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
  (func $f32x4.add (param $0 v128) (param $1 v128) (result v128)
   (f32x4.add
    (local.get $0)
@@ -1006,6 +1204,26 @@
    (local.get $2)
   )
  )
+ (func $i16x8.extadd_pairwise_i8x16_s (param $0 v128) (result v128)
+  (i16x8.extadd_pairwise_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $i16x8.extadd_pairwise_i8x16_u (param $0 v128) (result v128)
+  (i16x8.extadd_pairwise_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $i32x4.extadd_pairwise_i16x8_s (param $0 v128) (result v128)
+  (i32x4.extadd_pairwise_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $i32x4.extadd_pairwise_i16x8_u (param $0 v128) (result v128)
+  (i32x4.extadd_pairwise_i16x8_u
+   (local.get $0)
+  )
+ )
  (func $i32x4.trunc_sat_f32x4_s (param $0 v128) (result v128)
   (i32x4.trunc_sat_f32x4_s
    (local.get $0)
@@ -1130,6 +1348,26 @@
    (local.get $0)
   )
  )
+ (func $i64x2.widen_low_i32x4_s (param $0 v128) (result v128)
+  (i64x2.widen_low_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.widen_high_i32x4_s (param $0 v128) (result v128)
+  (i64x2.widen_high_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $i64x2.widen_low_i32x4_u (param $0 v128) (result v128)
+  (i64x2.widen_low_i32x4_u
+   (local.get $0)
+  )
+ )
+ (func $i64x2.widen_high_i32x4_u (param $0 v128) (result v128)
+  (i64x2.widen_high_i32x4_u
+   (local.get $0)
+  )
+ )
  (func $i16x8.load8x8_u (param $0 i32) (result v128)
   (i16x8.load8x8_u
    (local.get $0)
@@ -1174,6 +1412,16 @@
   (v8x16.swizzle
    (local.get $0)
    (local.get $1)
+  )
+ )
+ (func $prefetch.t (param $0 i32)
+  (prefetch.t offset=3 align=2
+   (local.get $0)
+  )
+ )
+ (func $prefetch.nt (param $0 i32)
+  (prefetch.nt offset=3 align=2
+   (local.get $0)
   )
  )
 )
diff --git a/binaryen/test/simd.wast.fromBinary.noDebugInfo b/binaryen/test/simd.wast.fromBinary.noDebugInfo
--- a/binaryen/test/simd.wast.fromBinary.noDebugInfo
+++ b/binaryen/test/simd.wast.fromBinary.noDebugInfo
@@ -1,12 +1,14 @@
 (module
  (type $v128_v128_=>_v128 (func (param v128 v128) (result v128)))
  (type $v128_=>_v128 (func (param v128) (result v128)))
- (type $v128_=>_i32 (func (param v128) (result i32)))
  (type $i32_=>_v128 (func (param i32) (result v128)))
+ (type $v128_=>_i32 (func (param v128) (result i32)))
  (type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
- (type $none_=>_v128 (func (result v128)))
  (type $v128_v128_v128_=>_v128 (func (param v128 v128 v128) (result v128)))
  (type $i32_v128_=>_none (func (param i32 v128)))
+ (type $i32_v128_=>_v128 (func (param i32 v128) (result v128)))
+ (type $none_=>_v128 (func (result v128)))
+ (type $i32_=>_none (func (param i32)))
  (type $v128_=>_i64 (func (param v128) (result i64)))
  (type $v128_=>_f32 (func (param v128) (result f32)))
  (type $v128_=>_f64 (func (param v128) (result f64)))
@@ -333,847 +335,1093 @@
   )
  )
  (func $58 (param $0 v128) (param $1 v128) (result v128)
-  (f32x4.eq
+  (i64x2.eq
    (local.get $0)
    (local.get $1)
   )
  )
  (func $59 (param $0 v128) (param $1 v128) (result v128)
-  (f32x4.ne
+  (f32x4.eq
    (local.get $0)
    (local.get $1)
   )
  )
  (func $60 (param $0 v128) (param $1 v128) (result v128)
-  (f32x4.lt
+  (f32x4.ne
    (local.get $0)
    (local.get $1)
   )
  )
  (func $61 (param $0 v128) (param $1 v128) (result v128)
-  (f32x4.gt
+  (f32x4.lt
    (local.get $0)
    (local.get $1)
   )
  )
  (func $62 (param $0 v128) (param $1 v128) (result v128)
-  (f32x4.le
+  (f32x4.gt
    (local.get $0)
    (local.get $1)
   )
  )
  (func $63 (param $0 v128) (param $1 v128) (result v128)
-  (f32x4.ge
+  (f32x4.le
    (local.get $0)
    (local.get $1)
   )
  )
  (func $64 (param $0 v128) (param $1 v128) (result v128)
-  (f64x2.eq
+  (f32x4.ge
    (local.get $0)
    (local.get $1)
   )
  )
  (func $65 (param $0 v128) (param $1 v128) (result v128)
-  (f64x2.ne
+  (f64x2.eq
    (local.get $0)
    (local.get $1)
   )
  )
  (func $66 (param $0 v128) (param $1 v128) (result v128)
-  (f64x2.lt
+  (f64x2.ne
    (local.get $0)
    (local.get $1)
   )
  )
  (func $67 (param $0 v128) (param $1 v128) (result v128)
-  (f64x2.gt
+  (f64x2.lt
    (local.get $0)
    (local.get $1)
   )
  )
  (func $68 (param $0 v128) (param $1 v128) (result v128)
-  (f64x2.le
+  (f64x2.gt
    (local.get $0)
    (local.get $1)
   )
  )
  (func $69 (param $0 v128) (param $1 v128) (result v128)
+  (f64x2.le
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $70 (param $0 v128) (param $1 v128) (result v128)
   (f64x2.ge
    (local.get $0)
    (local.get $1)
   )
  )
- (func $70 (param $0 v128) (result v128)
+ (func $71 (param $0 v128) (result v128)
   (v128.not
    (local.get $0)
   )
  )
- (func $71 (param $0 v128) (param $1 v128) (result v128)
+ (func $72 (param $0 v128) (param $1 v128) (result v128)
   (v128.and
    (local.get $0)
    (local.get $1)
   )
  )
- (func $72 (param $0 v128) (param $1 v128) (result v128)
+ (func $73 (param $0 v128) (param $1 v128) (result v128)
   (v128.or
    (local.get $0)
    (local.get $1)
   )
  )
- (func $73 (param $0 v128) (param $1 v128) (result v128)
+ (func $74 (param $0 v128) (param $1 v128) (result v128)
   (v128.xor
    (local.get $0)
    (local.get $1)
   )
  )
- (func $74 (param $0 v128) (param $1 v128) (result v128)
+ (func $75 (param $0 v128) (param $1 v128) (result v128)
   (v128.andnot
    (local.get $0)
    (local.get $1)
   )
  )
- (func $75 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+ (func $76 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
   (v128.bitselect
    (local.get $0)
    (local.get $1)
    (local.get $2)
   )
  )
- (func $76 (param $0 v128) (result v128)
+ (func $77 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v8x16.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $78 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v16x8.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $79 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v32x4.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $80 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+  (v64x2.signselect
+   (local.get $0)
+   (local.get $1)
+   (local.get $2)
+  )
+ )
+ (func $81 (param $0 i32) (param $1 v128) (result v128)
+  (v128.load8_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $82 (param $0 i32) (param $1 v128) (result v128)
+  (v128.load16_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $83 (param $0 i32) (param $1 v128) (result v128)
+  (v128.load32_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $84 (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $85 (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $86 (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $87 (param $0 i32) (param $1 v128) (result v128)
+  (v128.load64_lane offset=32 align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $88 (param $0 i32) (param $1 v128)
+  (v128.store8_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $89 (param $0 i32) (param $1 v128)
+  (v128.store16_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $90 (param $0 i32) (param $1 v128)
+  (v128.store32_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $91 (param $0 i32) (param $1 v128)
+  (v128.store64_lane 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $92 (param $0 i32) (param $1 v128)
+  (v128.store64_lane align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $93 (param $0 i32) (param $1 v128)
+  (v128.store64_lane offset=32 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $94 (param $0 i32) (param $1 v128)
+  (v128.store64_lane offset=32 align=1 0
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $95 (param $0 v128) (result v128)
+  (i8x16.popcnt
+   (local.get $0)
+  )
+ )
+ (func $96 (param $0 v128) (result v128)
   (i8x16.abs
    (local.get $0)
   )
  )
- (func $77 (param $0 v128) (result v128)
+ (func $97 (param $0 v128) (result v128)
   (i8x16.neg
    (local.get $0)
   )
  )
- (func $78 (param $0 v128) (result i32)
+ (func $98 (param $0 v128) (result i32)
   (i8x16.any_true
    (local.get $0)
   )
  )
- (func $79 (param $0 v128) (result i32)
+ (func $99 (param $0 v128) (result i32)
   (i8x16.all_true
    (local.get $0)
   )
  )
- (func $80 (param $0 v128) (result i32)
+ (func $100 (param $0 v128) (result i32)
   (i8x16.bitmask
    (local.get $0)
   )
  )
- (func $81 (param $0 v128) (param $1 i32) (result v128)
+ (func $101 (param $0 v128) (param $1 i32) (result v128)
   (i8x16.shl
    (local.get $0)
    (local.get $1)
   )
  )
- (func $82 (param $0 v128) (param $1 i32) (result v128)
+ (func $102 (param $0 v128) (param $1 i32) (result v128)
   (i8x16.shr_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $83 (param $0 v128) (param $1 i32) (result v128)
+ (func $103 (param $0 v128) (param $1 i32) (result v128)
   (i8x16.shr_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $84 (param $0 v128) (param $1 v128) (result v128)
+ (func $104 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.add
    (local.get $0)
    (local.get $1)
   )
  )
- (func $85 (param $0 v128) (param $1 v128) (result v128)
+ (func $105 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.add_saturate_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $86 (param $0 v128) (param $1 v128) (result v128)
+ (func $106 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.add_saturate_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $87 (param $0 v128) (param $1 v128) (result v128)
+ (func $107 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.sub
    (local.get $0)
    (local.get $1)
   )
  )
- (func $88 (param $0 v128) (param $1 v128) (result v128)
+ (func $108 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.sub_saturate_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $89 (param $0 v128) (param $1 v128) (result v128)
+ (func $109 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.sub_saturate_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $90 (param $0 v128) (param $1 v128) (result v128)
+ (func $110 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.mul
    (local.get $0)
    (local.get $1)
   )
  )
- (func $91 (param $0 v128) (param $1 v128) (result v128)
+ (func $111 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.min_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $92 (param $0 v128) (param $1 v128) (result v128)
+ (func $112 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.min_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $93 (param $0 v128) (param $1 v128) (result v128)
+ (func $113 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.max_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $94 (param $0 v128) (param $1 v128) (result v128)
+ (func $114 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.max_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $95 (param $0 v128) (param $1 v128) (result v128)
+ (func $115 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.avgr_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $96 (param $0 v128) (result v128)
+ (func $116 (param $0 v128) (result v128)
   (i16x8.abs
    (local.get $0)
   )
  )
- (func $97 (param $0 v128) (result v128)
+ (func $117 (param $0 v128) (result v128)
   (i16x8.neg
    (local.get $0)
   )
  )
- (func $98 (param $0 v128) (result i32)
+ (func $118 (param $0 v128) (result i32)
   (i16x8.any_true
    (local.get $0)
   )
  )
- (func $99 (param $0 v128) (result i32)
+ (func $119 (param $0 v128) (result i32)
   (i16x8.all_true
    (local.get $0)
   )
  )
- (func $100 (param $0 v128) (result i32)
+ (func $120 (param $0 v128) (result i32)
   (i16x8.bitmask
    (local.get $0)
   )
  )
- (func $101 (param $0 v128) (param $1 i32) (result v128)
+ (func $121 (param $0 v128) (param $1 i32) (result v128)
   (i16x8.shl
    (local.get $0)
    (local.get $1)
   )
  )
- (func $102 (param $0 v128) (param $1 i32) (result v128)
+ (func $122 (param $0 v128) (param $1 i32) (result v128)
   (i16x8.shr_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $103 (param $0 v128) (param $1 i32) (result v128)
+ (func $123 (param $0 v128) (param $1 i32) (result v128)
   (i16x8.shr_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $104 (param $0 v128) (param $1 v128) (result v128)
+ (func $124 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.add
    (local.get $0)
    (local.get $1)
   )
  )
- (func $105 (param $0 v128) (param $1 v128) (result v128)
+ (func $125 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.add_saturate_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $106 (param $0 v128) (param $1 v128) (result v128)
+ (func $126 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.add_saturate_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $107 (param $0 v128) (param $1 v128) (result v128)
+ (func $127 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.sub
    (local.get $0)
    (local.get $1)
   )
  )
- (func $108 (param $0 v128) (param $1 v128) (result v128)
+ (func $128 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.sub_saturate_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $109 (param $0 v128) (param $1 v128) (result v128)
+ (func $129 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.sub_saturate_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $110 (param $0 v128) (param $1 v128) (result v128)
+ (func $130 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.mul
    (local.get $0)
    (local.get $1)
   )
  )
- (func $111 (param $0 v128) (param $1 v128) (result v128)
+ (func $131 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.min_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $112 (param $0 v128) (param $1 v128) (result v128)
+ (func $132 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.min_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $113 (param $0 v128) (param $1 v128) (result v128)
+ (func $133 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.max_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $114 (param $0 v128) (param $1 v128) (result v128)
+ (func $134 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.max_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $115 (param $0 v128) (param $1 v128) (result v128)
+ (func $135 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.avgr_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $116 (param $0 v128) (result v128)
+ (func $136 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.q15mulr_sat_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $137 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_low_i8x16_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $138 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_high_i8x16_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $139 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_low_i8x16_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $140 (param $0 v128) (param $1 v128) (result v128)
+  (i16x8.extmul_high_i8x16_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $141 (param $0 v128) (result v128)
   (i32x4.abs
    (local.get $0)
   )
  )
- (func $117 (param $0 v128) (result v128)
+ (func $142 (param $0 v128) (result v128)
   (i32x4.neg
    (local.get $0)
   )
  )
- (func $118 (param $0 v128) (result i32)
+ (func $143 (param $0 v128) (result i32)
   (i32x4.any_true
    (local.get $0)
   )
  )
- (func $119 (param $0 v128) (result i32)
+ (func $144 (param $0 v128) (result i32)
   (i32x4.all_true
    (local.get $0)
   )
  )
- (func $120 (param $0 v128) (result i32)
+ (func $145 (param $0 v128) (result i32)
   (i32x4.bitmask
    (local.get $0)
   )
  )
- (func $121 (param $0 v128) (param $1 i32) (result v128)
+ (func $146 (param $0 v128) (param $1 i32) (result v128)
   (i32x4.shl
    (local.get $0)
    (local.get $1)
   )
  )
- (func $122 (param $0 v128) (param $1 i32) (result v128)
+ (func $147 (param $0 v128) (param $1 i32) (result v128)
   (i32x4.shr_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $123 (param $0 v128) (param $1 i32) (result v128)
+ (func $148 (param $0 v128) (param $1 i32) (result v128)
   (i32x4.shr_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $124 (param $0 v128) (param $1 v128) (result v128)
+ (func $149 (param $0 v128) (param $1 v128) (result v128)
   (i32x4.add
    (local.get $0)
    (local.get $1)
   )
  )
- (func $125 (param $0 v128) (param $1 v128) (result v128)
+ (func $150 (param $0 v128) (param $1 v128) (result v128)
   (i32x4.sub
    (local.get $0)
    (local.get $1)
   )
  )
- (func $126 (param $0 v128) (param $1 v128) (result v128)
+ (func $151 (param $0 v128) (param $1 v128) (result v128)
   (i32x4.mul
    (local.get $0)
    (local.get $1)
   )
  )
- (func $127 (param $0 v128) (param $1 v128) (result v128)
+ (func $152 (param $0 v128) (param $1 v128) (result v128)
   (i32x4.min_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $128 (param $0 v128) (param $1 v128) (result v128)
+ (func $153 (param $0 v128) (param $1 v128) (result v128)
   (i32x4.min_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $129 (param $0 v128) (param $1 v128) (result v128)
+ (func $154 (param $0 v128) (param $1 v128) (result v128)
   (i32x4.max_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $130 (param $0 v128) (param $1 v128) (result v128)
+ (func $155 (param $0 v128) (param $1 v128) (result v128)
   (i32x4.max_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $131 (param $0 v128) (param $1 v128) (result v128)
+ (func $156 (param $0 v128) (param $1 v128) (result v128)
   (i32x4.dot_i16x8_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $132 (param $0 v128) (result v128)
-  (i64x2.neg
+ (func $157 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_low_i16x8_s
    (local.get $0)
+   (local.get $1)
   )
  )
- (func $133 (param $0 v128) (result i32)
-  (i64x2.any_true
+ (func $158 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_high_i16x8_s
    (local.get $0)
+   (local.get $1)
   )
  )
- (func $134 (param $0 v128) (result i32)
-  (i64x2.all_true
+ (func $159 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_low_i16x8_u
    (local.get $0)
+   (local.get $1)
   )
  )
- (func $135 (param $0 v128) (param $1 i32) (result v128)
+ (func $160 (param $0 v128) (param $1 v128) (result v128)
+  (i32x4.extmul_high_i16x8_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $161 (param $0 v128) (result v128)
+  (i64x2.neg
+   (local.get $0)
+  )
+ )
+ (func $162 (param $0 v128) (result i32)
+  (i64x2.bitmask
+   (local.get $0)
+  )
+ )
+ (func $163 (param $0 v128) (param $1 i32) (result v128)
   (i64x2.shl
    (local.get $0)
    (local.get $1)
   )
  )
- (func $136 (param $0 v128) (param $1 i32) (result v128)
+ (func $164 (param $0 v128) (param $1 i32) (result v128)
   (i64x2.shr_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $137 (param $0 v128) (param $1 i32) (result v128)
+ (func $165 (param $0 v128) (param $1 i32) (result v128)
   (i64x2.shr_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $138 (param $0 v128) (param $1 v128) (result v128)
+ (func $166 (param $0 v128) (param $1 v128) (result v128)
   (i64x2.add
    (local.get $0)
    (local.get $1)
   )
  )
- (func $139 (param $0 v128) (param $1 v128) (result v128)
+ (func $167 (param $0 v128) (param $1 v128) (result v128)
   (i64x2.sub
    (local.get $0)
    (local.get $1)
   )
  )
- (func $140 (param $0 v128) (param $1 v128) (result v128)
+ (func $168 (param $0 v128) (param $1 v128) (result v128)
   (i64x2.mul
    (local.get $0)
    (local.get $1)
   )
  )
- (func $141 (param $0 v128) (param $1 v128) (result v128)
+ (func $169 (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_low_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $170 (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_high_i32x4_s
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $171 (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_low_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $172 (param $0 v128) (param $1 v128) (result v128)
+  (i64x2.extmul_high_i32x4_u
+   (local.get $0)
+   (local.get $1)
+  )
+ )
+ (func $173 (param $0 v128) (param $1 v128) (result v128)
   (f32x4.add
    (local.get $0)
    (local.get $1)
   )
  )
- (func $142 (param $0 v128) (param $1 v128) (result v128)
+ (func $174 (param $0 v128) (param $1 v128) (result v128)
   (f32x4.sub
    (local.get $0)
    (local.get $1)
   )
  )
- (func $143 (param $0 v128) (param $1 v128) (result v128)
+ (func $175 (param $0 v128) (param $1 v128) (result v128)
   (f32x4.mul
    (local.get $0)
    (local.get $1)
   )
  )
- (func $144 (param $0 v128) (param $1 v128) (result v128)
+ (func $176 (param $0 v128) (param $1 v128) (result v128)
   (f32x4.div
    (local.get $0)
    (local.get $1)
   )
  )
- (func $145 (param $0 v128) (param $1 v128) (result v128)
+ (func $177 (param $0 v128) (param $1 v128) (result v128)
   (f32x4.min
    (local.get $0)
    (local.get $1)
   )
  )
- (func $146 (param $0 v128) (param $1 v128) (result v128)
+ (func $178 (param $0 v128) (param $1 v128) (result v128)
   (f32x4.max
    (local.get $0)
    (local.get $1)
   )
  )
- (func $147 (param $0 v128) (param $1 v128) (result v128)
+ (func $179 (param $0 v128) (param $1 v128) (result v128)
   (f32x4.pmin
    (local.get $0)
    (local.get $1)
   )
  )
- (func $148 (param $0 v128) (param $1 v128) (result v128)
+ (func $180 (param $0 v128) (param $1 v128) (result v128)
   (f32x4.pmax
    (local.get $0)
    (local.get $1)
   )
  )
- (func $149 (param $0 v128) (result v128)
+ (func $181 (param $0 v128) (result v128)
   (f32x4.ceil
    (local.get $0)
   )
  )
- (func $150 (param $0 v128) (result v128)
+ (func $182 (param $0 v128) (result v128)
   (f32x4.floor
    (local.get $0)
   )
  )
- (func $151 (param $0 v128) (result v128)
+ (func $183 (param $0 v128) (result v128)
   (f32x4.trunc
    (local.get $0)
   )
  )
- (func $152 (param $0 v128) (result v128)
+ (func $184 (param $0 v128) (result v128)
   (f32x4.nearest
    (local.get $0)
   )
  )
- (func $153 (param $0 v128) (result v128)
+ (func $185 (param $0 v128) (result v128)
   (f32x4.abs
    (local.get $0)
   )
  )
- (func $154 (param $0 v128) (result v128)
+ (func $186 (param $0 v128) (result v128)
   (f32x4.neg
    (local.get $0)
   )
  )
- (func $155 (param $0 v128) (result v128)
+ (func $187 (param $0 v128) (result v128)
   (f32x4.sqrt
    (local.get $0)
   )
  )
- (func $156 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+ (func $188 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
   (f32x4.qfma
    (local.get $0)
    (local.get $1)
    (local.get $2)
   )
  )
- (func $157 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+ (func $189 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
   (f32x4.qfms
    (local.get $0)
    (local.get $1)
    (local.get $2)
   )
  )
- (func $158 (param $0 v128) (param $1 v128) (result v128)
+ (func $190 (param $0 v128) (param $1 v128) (result v128)
   (f64x2.add
    (local.get $0)
    (local.get $1)
   )
  )
- (func $159 (param $0 v128) (param $1 v128) (result v128)
+ (func $191 (param $0 v128) (param $1 v128) (result v128)
   (f64x2.sub
    (local.get $0)
    (local.get $1)
   )
  )
- (func $160 (param $0 v128) (param $1 v128) (result v128)
+ (func $192 (param $0 v128) (param $1 v128) (result v128)
   (f64x2.mul
    (local.get $0)
    (local.get $1)
   )
  )
- (func $161 (param $0 v128) (param $1 v128) (result v128)
+ (func $193 (param $0 v128) (param $1 v128) (result v128)
   (f64x2.div
    (local.get $0)
    (local.get $1)
   )
  )
- (func $162 (param $0 v128) (param $1 v128) (result v128)
+ (func $194 (param $0 v128) (param $1 v128) (result v128)
   (f64x2.min
    (local.get $0)
    (local.get $1)
   )
  )
- (func $163 (param $0 v128) (param $1 v128) (result v128)
+ (func $195 (param $0 v128) (param $1 v128) (result v128)
   (f64x2.max
    (local.get $0)
    (local.get $1)
   )
  )
- (func $164 (param $0 v128) (param $1 v128) (result v128)
+ (func $196 (param $0 v128) (param $1 v128) (result v128)
   (f64x2.pmin
    (local.get $0)
    (local.get $1)
   )
  )
- (func $165 (param $0 v128) (param $1 v128) (result v128)
+ (func $197 (param $0 v128) (param $1 v128) (result v128)
   (f64x2.pmax
    (local.get $0)
    (local.get $1)
   )
  )
- (func $166 (param $0 v128) (result v128)
+ (func $198 (param $0 v128) (result v128)
   (f64x2.ceil
    (local.get $0)
   )
  )
- (func $167 (param $0 v128) (result v128)
+ (func $199 (param $0 v128) (result v128)
   (f64x2.floor
    (local.get $0)
   )
  )
- (func $168 (param $0 v128) (result v128)
+ (func $200 (param $0 v128) (result v128)
   (f64x2.trunc
    (local.get $0)
   )
  )
- (func $169 (param $0 v128) (result v128)
+ (func $201 (param $0 v128) (result v128)
   (f64x2.nearest
    (local.get $0)
   )
  )
- (func $170 (param $0 v128) (result v128)
+ (func $202 (param $0 v128) (result v128)
   (f64x2.abs
    (local.get $0)
   )
  )
- (func $171 (param $0 v128) (result v128)
+ (func $203 (param $0 v128) (result v128)
   (f64x2.neg
    (local.get $0)
   )
  )
- (func $172 (param $0 v128) (result v128)
+ (func $204 (param $0 v128) (result v128)
   (f64x2.sqrt
    (local.get $0)
   )
  )
- (func $173 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+ (func $205 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
   (f64x2.qfma
    (local.get $0)
    (local.get $1)
    (local.get $2)
   )
  )
- (func $174 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+ (func $206 (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
   (f64x2.qfms
    (local.get $0)
    (local.get $1)
    (local.get $2)
   )
  )
- (func $175 (param $0 v128) (result v128)
+ (func $207 (param $0 v128) (result v128)
+  (i16x8.extadd_pairwise_i8x16_s
+   (local.get $0)
+  )
+ )
+ (func $208 (param $0 v128) (result v128)
+  (i16x8.extadd_pairwise_i8x16_u
+   (local.get $0)
+  )
+ )
+ (func $209 (param $0 v128) (result v128)
+  (i32x4.extadd_pairwise_i16x8_s
+   (local.get $0)
+  )
+ )
+ (func $210 (param $0 v128) (result v128)
+  (i32x4.extadd_pairwise_i16x8_u
+   (local.get $0)
+  )
+ )
+ (func $211 (param $0 v128) (result v128)
   (i32x4.trunc_sat_f32x4_s
    (local.get $0)
   )
  )
- (func $176 (param $0 v128) (result v128)
+ (func $212 (param $0 v128) (result v128)
   (i32x4.trunc_sat_f32x4_u
    (local.get $0)
   )
  )
- (func $177 (param $0 v128) (result v128)
+ (func $213 (param $0 v128) (result v128)
   (i64x2.trunc_sat_f64x2_s
    (local.get $0)
   )
  )
- (func $178 (param $0 v128) (result v128)
+ (func $214 (param $0 v128) (result v128)
   (i64x2.trunc_sat_f64x2_u
    (local.get $0)
   )
  )
- (func $179 (param $0 v128) (result v128)
+ (func $215 (param $0 v128) (result v128)
   (f32x4.convert_i32x4_s
    (local.get $0)
   )
  )
- (func $180 (param $0 v128) (result v128)
+ (func $216 (param $0 v128) (result v128)
   (f32x4.convert_i32x4_u
    (local.get $0)
   )
  )
- (func $181 (param $0 v128) (result v128)
+ (func $217 (param $0 v128) (result v128)
   (f64x2.convert_i64x2_s
    (local.get $0)
   )
  )
- (func $182 (param $0 v128) (result v128)
+ (func $218 (param $0 v128) (result v128)
   (f64x2.convert_i64x2_u
    (local.get $0)
   )
  )
- (func $183 (param $0 i32) (result v128)
+ (func $219 (param $0 i32) (result v128)
   (v8x16.load_splat
    (local.get $0)
   )
  )
- (func $184 (param $0 i32) (result v128)
+ (func $220 (param $0 i32) (result v128)
   (v16x8.load_splat
    (local.get $0)
   )
  )
- (func $185 (param $0 i32) (result v128)
+ (func $221 (param $0 i32) (result v128)
   (v32x4.load_splat
    (local.get $0)
   )
  )
- (func $186 (param $0 i32) (result v128)
+ (func $222 (param $0 i32) (result v128)
   (v64x2.load_splat
    (local.get $0)
   )
  )
- (func $187 (param $0 v128) (param $1 v128) (result v128)
+ (func $223 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.narrow_i16x8_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $188 (param $0 v128) (param $1 v128) (result v128)
+ (func $224 (param $0 v128) (param $1 v128) (result v128)
   (i8x16.narrow_i16x8_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $189 (param $0 v128) (param $1 v128) (result v128)
+ (func $225 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.narrow_i32x4_s
    (local.get $0)
    (local.get $1)
   )
  )
- (func $190 (param $0 v128) (param $1 v128) (result v128)
+ (func $226 (param $0 v128) (param $1 v128) (result v128)
   (i16x8.narrow_i32x4_u
    (local.get $0)
    (local.get $1)
   )
  )
- (func $191 (param $0 v128) (result v128)
+ (func $227 (param $0 v128) (result v128)
   (i16x8.widen_low_i8x16_s
    (local.get $0)
   )
  )
- (func $192 (param $0 v128) (result v128)
+ (func $228 (param $0 v128) (result v128)
   (i16x8.widen_high_i8x16_s
    (local.get $0)
   )
  )
- (func $193 (param $0 v128) (result v128)
+ (func $229 (param $0 v128) (result v128)
   (i16x8.widen_low_i8x16_u
    (local.get $0)
   )
  )
- (func $194 (param $0 v128) (result v128)
+ (func $230 (param $0 v128) (result v128)
   (i16x8.widen_high_i8x16_u
    (local.get $0)
   )
  )
- (func $195 (param $0 v128) (result v128)
+ (func $231 (param $0 v128) (result v128)
   (i32x4.widen_low_i16x8_s
    (local.get $0)
   )
  )
- (func $196 (param $0 v128) (result v128)
+ (func $232 (param $0 v128) (result v128)
   (i32x4.widen_high_i16x8_s
    (local.get $0)
   )
  )
- (func $197 (param $0 v128) (result v128)
+ (func $233 (param $0 v128) (result v128)
   (i32x4.widen_low_i16x8_u
    (local.get $0)
   )
  )
- (func $198 (param $0 v128) (result v128)
+ (func $234 (param $0 v128) (result v128)
   (i32x4.widen_high_i16x8_u
    (local.get $0)
   )
  )
- (func $199 (param $0 i32) (result v128)
+ (func $235 (param $0 v128) (result v128)
+  (i64x2.widen_low_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $236 (param $0 v128) (result v128)
+  (i64x2.widen_high_i32x4_s
+   (local.get $0)
+  )
+ )
+ (func $237 (param $0 v128) (result v128)
+  (i64x2.widen_low_i32x4_u
+   (local.get $0)
+  )
+ )
+ (func $238 (param $0 v128) (result v128)
+  (i64x2.widen_high_i32x4_u
+   (local.get $0)
+  )
+ )
+ (func $239 (param $0 i32) (result v128)
   (i16x8.load8x8_u
    (local.get $0)
   )
  )
- (func $200 (param $0 i32) (result v128)
+ (func $240 (param $0 i32) (result v128)
   (i16x8.load8x8_s
    (local.get $0)
   )
  )
- (func $201 (param $0 i32) (result v128)
+ (func $241 (param $0 i32) (result v128)
   (i32x4.load16x4_s
    (local.get $0)
   )
  )
- (func $202 (param $0 i32) (result v128)
+ (func $242 (param $0 i32) (result v128)
   (i32x4.load16x4_u
    (local.get $0)
   )
  )
- (func $203 (param $0 i32) (result v128)
+ (func $243 (param $0 i32) (result v128)
   (i64x2.load32x2_s
    (local.get $0)
   )
  )
- (func $204 (param $0 i32) (result v128)
+ (func $244 (param $0 i32) (result v128)
   (i64x2.load32x2_u
    (local.get $0)
   )
  )
- (func $205 (param $0 i32) (result v128)
+ (func $245 (param $0 i32) (result v128)
   (v128.load32_zero
    (local.get $0)
   )
  )
- (func $206 (param $0 i32) (result v128)
+ (func $246 (param $0 i32) (result v128)
   (v128.load64_zero
    (local.get $0)
   )
  )
- (func $207 (param $0 v128) (param $1 v128) (result v128)
+ (func $247 (param $0 v128) (param $1 v128) (result v128)
   (v8x16.swizzle
    (local.get $0)
    (local.get $1)
+  )
+ )
+ (func $248 (param $0 i32)
+  (prefetch.t offset=3 align=2
+   (local.get $0)
+  )
+ )
+ (func $249 (param $0 i32)
+  (prefetch.nt offset=3 align=2
+   (local.get $0)
   )
  )
 )
diff --git a/binaryen/test/spec/old_float_exprs.wast b/binaryen/test/spec/old_float_exprs.wast
--- a/binaryen/test/spec/old_float_exprs.wast
+++ b/binaryen/test/spec/old_float_exprs.wast
@@ -46,8 +46,8 @@
 
 (assert_return (invoke "f32.no_fold_add_zero" (f32.const -0.0)) (f32.const 0.0))
 (assert_return (invoke "f64.no_fold_add_zero" (f64.const -0.0)) (f64.const 0.0))
-(assert_return (invoke "f32.no_fold_add_zero" (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f64.no_fold_add_zero" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f32.no_fold_add_zero" (f32.const nan:0x200000)) (f32.const nan:0x400000))
+(assert_return (invoke "f64.no_fold_add_zero" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that 0.0 - x is not folded to -x.
 
@@ -60,8 +60,8 @@
 
 (assert_return (invoke "f32.no_fold_zero_sub" (f32.const 0.0)) (f32.const 0.0))
 (assert_return (invoke "f64.no_fold_zero_sub" (f64.const 0.0)) (f64.const 0.0))
-(assert_return (invoke "f32.no_fold_zero_sub" (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f64.no_fold_zero_sub" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f32.no_fold_zero_sub" (f32.const nan:0x200000)) (f32.const nan:0x400000))
+(assert_return (invoke "f64.no_fold_zero_sub" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that x - 0.0 is not folded to x.
 
@@ -72,8 +72,8 @@
     (f64.sub (local.get $x) (f64.const 0.0)))
 )
 
-(assert_return (invoke "f32.no_fold_sub_zero" (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f64.no_fold_sub_zero" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f32.no_fold_sub_zero" (f32.const nan:0x200000)) (f32.const nan:0x400000))
+(assert_return (invoke "f64.no_fold_sub_zero" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that x*0.0 is not folded to 0.0.
 
@@ -87,11 +87,11 @@
 (assert_return (invoke "f32.no_fold_mul_zero" (f32.const -0.0)) (f32.const -0.0))
 (assert_return (invoke "f32.no_fold_mul_zero" (f32.const -1.0)) (f32.const -0.0))
 (assert_return (invoke "f32.no_fold_mul_zero" (f32.const -2.0)) (f32.const -0.0))
-(assert_return (invoke "f32.no_fold_mul_zero" (f32.const nan:0x200000)) (f32.const nan:0x600000))
+(assert_return (invoke "f32.no_fold_mul_zero" (f32.const nan:0x200000)) (f32.const nan:0x400000))
 (assert_return (invoke "f64.no_fold_mul_zero" (f64.const -0.0)) (f64.const -0.0))
 (assert_return (invoke "f64.no_fold_mul_zero" (f64.const -1.0)) (f64.const -0.0))
 (assert_return (invoke "f64.no_fold_mul_zero" (f64.const -2.0)) (f64.const -0.0))
-(assert_return (invoke "f64.no_fold_mul_zero" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f64.no_fold_mul_zero" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that x*1.0 is not folded to x.
 ;; See IEEE 754-2008 10.4 "Literal meaning and value-changing optimizations".
@@ -103,8 +103,8 @@
     (f64.mul (local.get $x) (f64.const 1.0)))
 )
 
-(assert_return (invoke "f32.no_fold_mul_one" (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f64.no_fold_mul_one" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f32.no_fold_mul_one" (f32.const nan:0x200000)) (f32.const nan:0x400000))
+(assert_return (invoke "f64.no_fold_mul_one" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that 0.0/x is not folded to 0.0.
 
@@ -118,11 +118,11 @@
 (assert_return_nan (invoke "f32.no_fold_zero_div" (f32.const 0.0)))
 (assert_return_nan (invoke "f32.no_fold_zero_div" (f32.const -0.0)))
 (assert_return (invoke "f32.no_fold_zero_div" (f32.const nan)) (f32.const nan))
-(assert_return (invoke "f32.no_fold_zero_div" (f32.const nan:0x200000)) (f32.const nan:0x600000))
+(assert_return (invoke "f32.no_fold_zero_div" (f32.const nan:0x200000)) (f32.const nan:0x400000))
 (assert_return_nan (invoke "f64.no_fold_zero_div" (f64.const 0.0)))
 (assert_return_nan (invoke "f64.no_fold_zero_div" (f64.const -0.0)))
 (assert_return (invoke "f64.no_fold_zero_div" (f64.const nan)) (f64.const nan))
-(assert_return (invoke "f64.no_fold_zero_div" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f64.no_fold_zero_div" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that x/1.0 is not folded to x.
 
@@ -133,8 +133,8 @@
     (f64.div (local.get $x) (f64.const 1.0)))
 )
 
-(assert_return (invoke "f32.no_fold_div_one" (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f64.no_fold_div_one" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f32.no_fold_div_one" (f32.const nan:0x200000)) (f32.const nan:0x400000))
+(assert_return (invoke "f64.no_fold_div_one" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that x/-1.0 is not folded to -x.
 
@@ -145,8 +145,8 @@
     (f64.div (local.get $x) (f64.const -1.0)))
 )
 
-(assert_return (invoke "f32.no_fold_div_neg1" (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f64.no_fold_div_neg1" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f32.no_fold_div_neg1" (f32.const nan:0x200000)) (f32.const nan:0x400000))
+(assert_return (invoke "f64.no_fold_div_neg1" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that -0.0 - x is not folded to -x.
 
@@ -157,8 +157,8 @@
     (f64.sub (f64.const -0.0) (local.get $x)))
 )
 
-(assert_return (invoke "f32.no_fold_neg0_sub" (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f64.no_fold_neg0_sub" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f32.no_fold_neg0_sub" (f32.const nan:0x200000)) (f32.const nan:0x400000))
+(assert_return (invoke "f64.no_fold_neg0_sub" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that -1.0 * x is not folded to -x.
 
@@ -169,8 +169,8 @@
     (f64.mul (f64.const -1.0) (local.get $x)))
 )
 
-(assert_return (invoke "f32.no_fold_neg1_mul" (f32.const nan:0x200000)) (f32.const nan:0x600000))
-(assert_return (invoke "f64.no_fold_neg1_mul" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f32.no_fold_neg1_mul" (f32.const nan:0x200000)) (f32.const nan:0x400000))
+(assert_return (invoke "f64.no_fold_neg1_mul" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that x == x is not folded to true.
 
@@ -365,7 +365,7 @@
 (assert_return (invoke "f32.no_fold_div_0" (f32.const -infinity)) (f32.const -infinity))
 (assert_return_nan (invoke "f32.no_fold_div_0" (f32.const 0)))
 (assert_return_nan (invoke "f32.no_fold_div_0" (f32.const -0)))
-(assert_return (invoke "f32.no_fold_div_0" (f32.const nan:0x200000)) (f32.const nan:0x600000))
+(assert_return (invoke "f32.no_fold_div_0" (f32.const nan:0x200000)) (f32.const nan:0x400000))
 (assert_return (invoke "f32.no_fold_div_0" (f32.const nan)) (f32.const nan))
 (assert_return (invoke "f64.no_fold_div_0" (f64.const 1.0)) (f64.const infinity))
 (assert_return (invoke "f64.no_fold_div_0" (f64.const -1.0)) (f64.const -infinity))
@@ -374,7 +374,7 @@
 (assert_return_nan (invoke "f64.no_fold_div_0" (f64.const 0)))
 (assert_return_nan (invoke "f64.no_fold_div_0" (f64.const -0)))
 (assert_return (invoke "f64.no_fold_div_0" (f64.const nan)) (f64.const nan))
-(assert_return (invoke "f64.no_fold_div_0" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f64.no_fold_div_0" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that x/-0 is not folded away.
 
@@ -391,7 +391,7 @@
 (assert_return (invoke "f32.no_fold_div_neg0" (f32.const -infinity)) (f32.const infinity))
 (assert_return_nan (invoke "f32.no_fold_div_neg0" (f32.const 0)))
 (assert_return_nan (invoke "f32.no_fold_div_neg0" (f32.const -0)))
-(assert_return (invoke "f32.no_fold_div_neg0" (f32.const nan:0x200000)) (f32.const nan:0x600000))
+(assert_return (invoke "f32.no_fold_div_neg0" (f32.const nan:0x200000)) (f32.const nan:0x400000))
 (assert_return (invoke "f32.no_fold_div_neg0" (f32.const nan)) (f32.const nan))
 (assert_return (invoke "f64.no_fold_div_neg0" (f64.const 1.0)) (f64.const -infinity))
 (assert_return (invoke "f64.no_fold_div_neg0" (f64.const -1.0)) (f64.const infinity))
@@ -400,7 +400,7 @@
 (assert_return_nan (invoke "f64.no_fold_div_neg0" (f64.const 0)))
 (assert_return_nan (invoke "f64.no_fold_div_neg0" (f64.const -0)))
 (assert_return (invoke "f64.no_fold_div_neg0" (f64.const nan)) (f64.const nan))
-(assert_return (invoke "f64.no_fold_div_neg0" (f64.const nan:0x4000000000000)) (f64.const nan:0xc000000000000))
+(assert_return (invoke "f64.no_fold_div_neg0" (f64.const nan:0x4000000000000)) (f64.const nan:0x8000000000000))
 
 ;; Test that sqrt(x*x+y*y) is not folded to hypot.
 
diff --git a/binaryen/test/spec/old_import.wast b/binaryen/test/spec/old_import.wast
--- a/binaryen/test/spec/old_import.wast
+++ b/binaryen/test/spec/old_import.wast
@@ -54,11 +54,11 @@
 ;; Globals
 
 (module
-  (import "spectest" "global" (global i32))
-  (global (import "spectest" "global") i32)
+  (import "spectest" "global_i32" (global i32))
+  (global (import "spectest" "global_i32") i32)
 
-  (import "spectest" "global" (global $x i32))
-  (global $y (import "spectest" "global") i32)
+  (import "spectest" "global_i32" (global $x i32))
+  (global $y (import "spectest" "global_i32") i32)
 
   (func (export "get-0") (result i32) (global.get 0))
   (func (export "get-1") (result i32) (global.get 1))
@@ -86,9 +86,9 @@
   "type mismatch"
 )
 
-(module (import "spectest" "global" (global i64)))
-(module (import "spectest" "global" (global f32)))
-(module (import "spectest" "global" (global f64)))
+(module (import "spectest" "global_i64" (global i64)))
+(module (import "spectest" "global_i64" (global f32)))
+(module (import "spectest" "global_i64" (global f64)))
 
 
 ;; Tables
diff --git a/binaryen/test/spec/simd.wast b/binaryen/test/spec/simd.wast
--- a/binaryen/test/spec/simd.wast
+++ b/binaryen/test/spec/simd.wast
@@ -2,6 +2,7 @@
  (memory 1)
  (data (i32.const 128) "WASMSIMDGOESFAST")
  (data (i32.const 256) "\80\90\a0\b0\c0\d0\e0\f0")
+ (data (i32.const 1024) "\ff\ff\ff\ff\ff\ff\ff\ff")
  (func (export "v128.load") (param $0 i32) (result v128) (v128.load (local.get $0)))
  (func (export "v128.store") (param $0 i32) (param $1 v128) (result v128)
    (v128.store offset=0 align=16 (local.get $0) (local.get $1))
@@ -83,6 +84,7 @@
  (func (export "i32x4.le_u") (param $0 v128) (param $1 v128) (result v128) (i32x4.le_u (local.get $0) (local.get $1)))
  (func (export "i32x4.ge_s") (param $0 v128) (param $1 v128) (result v128) (i32x4.ge_s (local.get $0) (local.get $1)))
  (func (export "i32x4.ge_u") (param $0 v128) (param $1 v128) (result v128) (i32x4.ge_u (local.get $0) (local.get $1)))
+ (func (export "i64x2.eq") (param $0 v128) (param $1 v128) (result v128) (i64x2.eq (local.get $0) (local.get $1)))
  (func (export "f32x4.eq") (param $0 v128) (param $1 v128) (result v128) (f32x4.eq (local.get $0) (local.get $1)))
  (func (export "f32x4.ne") (param $0 v128) (param $1 v128) (result v128) (f32x4.ne (local.get $0) (local.get $1)))
  (func (export "f32x4.lt") (param $0 v128) (param $1 v128) (result v128) (f32x4.lt (local.get $0) (local.get $1)))
@@ -103,6 +105,27 @@
  (func (export "v128.bitselect") (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
    (v128.bitselect (local.get $0) (local.get $1) (local.get $2))
  )
+ (func (export "v8x16.signselect") (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+   (v8x16.signselect (local.get $0) (local.get $1) (local.get $2))
+ )
+ (func (export "v16x8.signselect") (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+   (v16x8.signselect (local.get $0) (local.get $1) (local.get $2))
+ )
+ (func (export "v32x4.signselect") (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+   (v32x4.signselect (local.get $0) (local.get $1) (local.get $2))
+ )
+ (func (export "v64x2.signselect") (param $0 v128) (param $1 v128) (param $2 v128) (result v128)
+   (v64x2.signselect (local.get $0) (local.get $1) (local.get $2))
+ )
+ (func (export "v128.load8_lane") (param $0 i32) (param $1 v128) (result v128) (v128.load8_lane 0 (local.get $0) (local.get $1)))
+ (func (export "v128.load16_lane") (param $0 i32) (param $1 v128) (result v128) (v128.load16_lane 0 (local.get $0) (local.get $1)))
+ (func (export "v128.load32_lane") (param $0 i32) (param $1 v128) (result v128) (v128.load32_lane 0 (local.get $0) (local.get $1)))
+ (func (export "v128.load64_lane") (param $0 i32) (param $1 v128) (result v128) (v128.load64_lane 0 (local.get $0) (local.get $1)))
+ (func (export "v128.store8_lane") (param $0 i32) (param $1 v128) (v128.store8_lane 0 (local.get $0) (local.get $1)))
+ (func (export "v128.store16_lane") (param $0 i32) (param $1 v128) (v128.store16_lane 0 (local.get $0) (local.get $1)))
+ (func (export "v128.store32_lane") (param $0 i32) (param $1 v128) (v128.store32_lane 0 (local.get $0) (local.get $1)))
+ (func (export "v128.store64_lane") (param $0 i32) (param $1 v128) (v128.store64_lane 0 (local.get $0) (local.get $1)))
+ (func (export "i8x16.popcnt") (param $0 v128) (result v128) (i8x16.popcnt (local.get $0)))
  (func (export "i8x16.abs") (param $0 v128) (result v128) (i8x16.abs (local.get $0)))
  (func (export "i8x16.neg") (param $0 v128) (result v128) (i8x16.neg (local.get $0)))
  (func (export "i8x16.any_true") (param $0 v128) (result i32) (i8x16.any_true (local.get $0)))
@@ -143,6 +166,8 @@
  (func (export "i16x8.max_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.max_s (local.get $0) (local.get $1)))
  (func (export "i16x8.max_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.max_u (local.get $0) (local.get $1)))
  (func (export "i16x8.avgr_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.avgr_u (local.get $0) (local.get $1)))
+ ;; TODO: Q15 rounding, saturating multiplication
+ ;; TODO: extending multiplications
  (func (export "i32x4.abs") (param $0 v128) (result v128) (i32x4.abs (local.get $0)))
  (func (export "i32x4.neg") (param $0 v128) (result v128) (i32x4.neg (local.get $0)))
  (func (export "i32x4.any_true") (param $0 v128) (result i32) (i32x4.any_true (local.get $0)))
@@ -160,8 +185,7 @@
  (func (export "i32x4.max_u") (param $0 v128) (param $1 v128) (result v128) (i32x4.max_u (local.get $0) (local.get $1)))
  (func (export "i32x4.dot_i16x8_s") (param $0 v128) (param $1 v128) (result v128) (i32x4.dot_i16x8_s (local.get $0) (local.get $1)))
  (func (export "i64x2.neg") (param $0 v128) (result v128) (i64x2.neg (local.get $0)))
- (func (export "i64x2.any_true") (param $0 v128) (result i32) (i64x2.any_true (local.get $0)))
- (func (export "i64x2.all_true") (param $0 v128) (result i32) (i64x2.all_true (local.get $0)))
+ (func (export "i64x2.bitmask") (param $0 v128) (result i32) (i64x2.bitmask (local.get $0)))
  (func (export "i64x2.shl") (param $0 v128) (param $1 i32) (result v128) (i64x2.shl (local.get $0) (local.get $1)))
  (func (export "i64x2.shr_s") (param $0 v128) (param $1 i32) (result v128) (i64x2.shr_s (local.get $0) (local.get $1)))
  (func (export "i64x2.shr_u") (param $0 v128) (param $1 i32) (result v128) (i64x2.shr_u (local.get $0) (local.get $1)))
@@ -202,6 +226,7 @@
  (func (export "f64x2.floor") (param $0 v128) (result v128) (f64x2.floor (local.get $0)))
  (func (export "f64x2.trunc") (param $0 v128) (result v128) (f64x2.trunc (local.get $0)))
  (func (export "f64x2.nearest") (param $0 v128) (result v128) (f64x2.nearest (local.get $0)))
+ ;; TODO: Extending pairwise adds once they have interpreter support
  (func (export "i32x4.trunc_sat_f32x4_s") (param $0 v128) (result v128) (i32x4.trunc_sat_f32x4_s (local.get $0)))
  (func (export "i32x4.trunc_sat_f32x4_u") (param $0 v128) (result v128) (i32x4.trunc_sat_f32x4_u (local.get $0)))
  (func (export "i64x2.trunc_sat_f64x2_s") (param $0 v128) (result v128) (i64x2.trunc_sat_f64x2_s (local.get $0)))
@@ -226,6 +251,10 @@
  (func (export "i32x4.widen_high_i16x8_s") (param $0 v128) (result v128) (i32x4.widen_high_i16x8_s (local.get $0)))
  (func (export "i32x4.widen_low_i16x8_u") (param $0 v128) (result v128) (i32x4.widen_low_i16x8_u (local.get $0)))
  (func (export "i32x4.widen_high_i16x8_u") (param $0 v128) (result v128) (i32x4.widen_high_i16x8_u (local.get $0)))
+ (func (export "i64x2.widen_low_i32x4_s") (param $0 v128) (result v128) (i64x2.widen_low_i32x4_s (local.get $0)))
+ (func (export "i64x2.widen_high_i32x4_s") (param $0 v128) (result v128) (i64x2.widen_high_i32x4_s (local.get $0)))
+ (func (export "i64x2.widen_low_i32x4_u") (param $0 v128) (result v128) (i64x2.widen_low_i32x4_u (local.get $0)))
+ (func (export "i64x2.widen_high_i32x4_u") (param $0 v128) (result v128) (i64x2.widen_high_i32x4_u (local.get $0)))
  (func (export "i16x8.load8x8_u") (param $0 i32) (result v128) (i16x8.load8x8_u (local.get $0)))
  (func (export "i16x8.load8x8_s") (param $0 i32) (result v128) (i16x8.load8x8_s (local.get $0)))
  (func (export "i32x4.load16x4_u") (param $0 i32) (result v128) (i32x4.load16x4_u (local.get $0)))
@@ -462,6 +491,9 @@
 (assert_return (invoke "i32x4.ge_s" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 -1 0 -1 0))
 (assert_return (invoke "i32x4.ge_u" (v128.const i32x4 0 -1 53 -7) (v128.const i32x4 0 53 -7 -1)) (v128.const i32x4 -1 -1 0 0))
 
+;; i64x2 comparisons
+(assert_return (invoke "i64x2.eq" (v128.const i64x2 0 -1) (v128.const i64x2 -1 -1)) (v128.const i64x2 0 -1))
+
 ;; f32x4 comparisons
 (assert_return (invoke "f32x4.eq" (v128.const f32x4 0 -1 1 0) (v128.const f32x4 0 0 -1 1)) (v128.const i32x4 -1 0 0 0))
 (assert_return (invoke "f32x4.ne" (v128.const f32x4 0 -1 1 0) (v128.const f32x4 0 0 -1 1)) (v128.const i32x4 0 -1 -1 -1))
@@ -509,8 +541,62 @@
   )
   (v128.const i32x4 0xABABABAB 0xAAAAAAAA 0xBBBBBBBB 0xAABBAABB)
 )
+;; TODO: signselect tests
 
+;; load/store lane
+(assert_return (invoke "v128.load8_lane"
+    (i32.const 1024)
+    (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+  )
+  (v128.const i32x4 0x040302ff 0x08070605 0x0c0b0a09 0x100f0e0d)
+)
+(assert_return (invoke "v128.load16_lane"
+    (i32.const 1024)
+    (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+  )
+  (v128.const i32x4 0x0403ffff 0x08070605 0x0c0b0a09 0x100f0e0d)
+)
+(assert_return (invoke "v128.load32_lane"
+    (i32.const 1024)
+    (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+  )
+  (v128.const i32x4 0xffffffff 0x08070605 0x0c0b0a09 0x100f0e0d)
+)
+(assert_return (invoke "v128.load64_lane"
+    (i32.const 1024)
+    (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+  )
+  (v128.const i32x4 0xffffffff 0xffffffff 0x0c0b0a09 0x100f0e0d)
+)
+(assert_return (invoke "v128.store8_lane"
+    (i32.const 1024)
+    (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+  )
+)
+(assert_return (invoke "v128.load" (i32.const 1024)) (v128.const i32x4 0xffffff01 0xffffffff 0x00000000 0x00000000))
+(assert_return (invoke "v128.store16_lane"
+    (i32.const 1024)
+    (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+  )
+)
+(assert_return (invoke "v128.load" (i32.const 1024)) (v128.const i32x4 0xffff0201 0xffffffff 0x00000000 0x00000000))
+(assert_return (invoke "v128.store32_lane"
+    (i32.const 1024)
+    (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+  )
+)
+(assert_return (invoke "v128.load" (i32.const 1024)) (v128.const i32x4 0x04030201 0xffffffff 0x00000000 0x00000000))
+(assert_return (invoke "v128.store64_lane"
+    (i32.const 1024)
+    (v128.const i32x4 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d)
+  )
+)
+(assert_return (invoke "v128.load" (i32.const 1024)) (v128.const i32x4 0x04030201 0x08070605 0x00000000 0x00000000))
+
 ;; i8x16 arithmetic
+(assert_return (invoke "i8x16.popcnt" (v128.const i8x16 0 1 42 -3 -56 127 -128 -126 0 -1 -42 3 56 -127 -128 126))
+  (v128.const i8x16 0 1 3 7 3 7 1 2 0 8 5 2 3 2 1 6)
+)
 (assert_return (invoke "i8x16.abs" (v128.const i8x16 0 1 42 -3 -56 127 -128 -126 0 -1 -42 3 56 -127 -128 126))
   (v128.const i8x16 0 1 42 3 56 127 -128 126 0 1 42 3 56 127 -128 126)
 )
@@ -780,12 +866,7 @@
 
 ;; i64x2 arithmetic
 (assert_return (invoke "i64x2.neg" (v128.const i64x2 0x8000000000000000 42)) (v128.const i64x2 0x8000000000000000 -42))
-(assert_return (invoke "i64x2.any_true" (v128.const i64x2 0 0)) (i32.const 0))
-(assert_return (invoke "i64x2.any_true" (v128.const i64x2 1 0)) (i32.const 1))
-(assert_return (invoke "i64x2.any_true" (v128.const i64x2 1 1)) (i32.const 1))
-(assert_return (invoke "i64x2.all_true" (v128.const i64x2 0 0)) (i32.const 0))
-(assert_return (invoke "i64x2.all_true" (v128.const i64x2 1 0)) (i32.const 0))
-(assert_return (invoke "i64x2.all_true" (v128.const i64x2 1 1)) (i32.const 1))
+;; TODO: test i64x2.bitmask
 (assert_return (invoke "i64x2.shl" (v128.const i64x2 1 0x8000000000000000) (i32.const 1)) (v128.const i64x2 2 0))
 (assert_return (invoke "i64x2.shl" (v128.const i64x2 1 0x8000000000000000) (i32.const 64)) (v128.const i64x2 1 0x8000000000000000))
 (assert_return (invoke "i64x2.shr_s" (v128.const i64x2 1 0x8000000000000000) (i32.const 1)) (v128.const i64x2 0 0xc000000000000000))
@@ -801,10 +882,10 @@
 (assert_return (invoke "f32x4.neg" (v128.const f32x4 -0 nan -infinity 5)) (v128.const f32x4 0 -nan infinity -5))
 (assert_return (invoke "f32x4.sqrt" (v128.const f32x4 -0 nan infinity 4)) (v128.const f32x4 -0 nan infinity 2))
 ;; TODO: qfma/qfms tests
-(assert_return (invoke "f32x4.add" (v128.const f32x4 nan -nan infinity 42) (v128.const f32x4 42 infinity infinity 1)) (v128.const f32x4 nan -nan infinity 43))
-(assert_return (invoke "f32x4.sub" (v128.const f32x4 nan -nan infinity 42) (v128.const f32x4 42 infinity -infinity 1)) (v128.const f32x4 nan -nan infinity 41))
-(assert_return (invoke "f32x4.mul" (v128.const f32x4 nan -nan infinity 42) (v128.const f32x4 42 infinity infinity 2)) (v128.const f32x4 nan -nan infinity 84))
-(assert_return (invoke "f32x4.div" (v128.const f32x4 nan -nan infinity 42) (v128.const f32x4 42 infinity 2 2)) (v128.const f32x4 nan -nan infinity 21))
+(assert_return (invoke "f32x4.add" (v128.const f32x4 nan -nan infinity 42) (v128.const f32x4 42 infinity infinity 1)) (v128.const f32x4 nan nan infinity 43))
+(assert_return (invoke "f32x4.sub" (v128.const f32x4 nan -nan infinity 42) (v128.const f32x4 42 infinity -infinity 1)) (v128.const f32x4 nan nan infinity 41))
+(assert_return (invoke "f32x4.mul" (v128.const f32x4 nan -nan infinity 42) (v128.const f32x4 42 infinity infinity 2)) (v128.const f32x4 nan nan infinity 84))
+(assert_return (invoke "f32x4.div" (v128.const f32x4 nan -nan infinity 42) (v128.const f32x4 42 infinity 2 2)) (v128.const f32x4 nan nan infinity 21))
 (assert_return (invoke "f32x4.min" (v128.const f32x4 -0 0 nan 5) (v128.const f32x4 0 -0 5 nan)) (v128.const f32x4 -0 -0 nan nan))
 (assert_return (invoke "f32x4.max" (v128.const f32x4 -0 0 nan 5) (v128.const f32x4 0 -0 5 nan)) (v128.const f32x4 0 0 nan nan))
 (assert_return (invoke "f32x4.pmin" (v128.const f32x4 -0 0 nan 5) (v128.const f32x4 0 -0 5 nan)) (v128.const f32x4 -0 0 nan 5))
@@ -830,13 +911,13 @@
 (assert_return (invoke "f64x2.sqrt" (v128.const f64x2 -0 nan)) (v128.const f64x2 -0 nan))
 (assert_return (invoke "f64x2.sqrt" (v128.const f64x2 infinity 4)) (v128.const f64x2 infinity 2))
 ;; TODO: qfma/qfms tests
-(assert_return (invoke "f64x2.add" (v128.const f64x2 nan -nan) (v128.const f64x2 42 infinity)) (v128.const f64x2 nan -nan))
+(assert_return (invoke "f64x2.add" (v128.const f64x2 nan -nan) (v128.const f64x2 42 infinity)) (v128.const f64x2 nan nan))
 (assert_return (invoke "f64x2.add" (v128.const f64x2 infinity 42) (v128.const f64x2 infinity 1)) (v128.const f64x2 infinity 43))
-(assert_return (invoke "f64x2.sub" (v128.const f64x2 nan -nan) (v128.const f64x2 42 infinity)) (v128.const f64x2 nan -nan))
+(assert_return (invoke "f64x2.sub" (v128.const f64x2 nan -nan) (v128.const f64x2 42 infinity)) (v128.const f64x2 nan nan))
 (assert_return (invoke "f64x2.sub" (v128.const f64x2 infinity 42) (v128.const f64x2 -infinity 1)) (v128.const f64x2 infinity 41))
-(assert_return (invoke "f64x2.mul" (v128.const f64x2 nan -nan) (v128.const f64x2 42 infinity)) (v128.const f64x2 nan -nan))
+(assert_return (invoke "f64x2.mul" (v128.const f64x2 nan -nan) (v128.const f64x2 42 infinity)) (v128.const f64x2 nan nan))
 (assert_return (invoke "f64x2.mul" (v128.const f64x2 infinity 42) (v128.const f64x2 infinity 2)) (v128.const f64x2 infinity 84))
-(assert_return (invoke "f64x2.div" (v128.const f64x2 nan -nan) (v128.const f64x2 42 infinity)) (v128.const f64x2 nan -nan))
+(assert_return (invoke "f64x2.div" (v128.const f64x2 nan -nan) (v128.const f64x2 42 infinity)) (v128.const f64x2 nan nan))
 (assert_return (invoke "f64x2.div" (v128.const f64x2 infinity 42) (v128.const f64x2 2 2)) (v128.const f64x2 infinity 21))
 (assert_return (invoke "f64x2.min" (v128.const f64x2 -0 0) (v128.const f64x2 0 -0)) (v128.const f64x2 -0 -0))
 (assert_return (invoke "f64x2.min" (v128.const f64x2 nan 5) (v128.const f64x2 5 nan)) (v128.const f64x2 nan nan))
@@ -940,6 +1021,7 @@
 (assert_return (invoke "i32x4.widen_high_i16x8_s" (v128.const i16x8 0 1 -1 32768 32767 32769 16384 -16384)) (v128.const i32x4 32767 -32767 16384 -16384))
 (assert_return (invoke "i32x4.widen_low_i16x8_u" (v128.const i16x8 0 1 -1 32768 32767 32769 16384 -16384)) (v128.const i32x4 0 1 65535 32768))
 (assert_return (invoke "i32x4.widen_high_i16x8_u" (v128.const i16x8 0 1 -1 32768 32767 32769 16384 -16384)) (v128.const i32x4 32767 32769 16384 49152))
+;; TODO: test i64x2 widens
 (assert_return (invoke "i16x8.load8x8_s" (i32.const 256)) (v128.const i16x8 0xff80 0xff90 0xffa0 0xffb0 0xffc0 0xffd0 0xffe0 0xfff0))
 (assert_return (invoke "i16x8.load8x8_u" (i32.const 256)) (v128.const i16x8 0x0080 0x0090 0x00a0 0x00b0 0x00c0 0x00d0 0x00e0 0x00f0))
 (assert_return (invoke "i32x4.load16x4_s" (i32.const 256)) (v128.const i32x4 0xffff9080 0xffffb0a0 0xffffd0c0 0xfffff0e0))
diff --git a/binaryen/test/threads.asm.js b/binaryen/test/threads.asm.js
deleted file mode 100644
--- a/binaryen/test/threads.asm.js
+++ /dev/null
@@ -1,147 +0,0 @@
-Module["asm"] =  (function(global, env, buffer) {
-  'use asm';
-
-
-  var HEAP8 = new global.Int8Array(buffer);
-  var HEAP16 = new global.Int16Array(buffer);
-  var HEAP32 = new global.Int32Array(buffer);
-  var HEAPU8 = new global.Uint8Array(buffer);
-  var HEAPU16 = new global.Uint16Array(buffer);
-  var HEAPU32 = new global.Uint32Array(buffer);
-  var HEAPF32 = new global.Float32Array(buffer);
-  var HEAPF64 = new global.Float64Array(buffer);
-
-  var DYNAMICTOP_PTR=env.DYNAMICTOP_PTR|0;
-  var tempDoublePtr=env.tempDoublePtr|0;
-  var ABORT=env.ABORT|0;
-  var STACKTOP=env.STACKTOP|0;
-  var STACK_MAX=env.STACK_MAX|0;
-
-  var __THREW__ = 0;
-  var threwValue = 0;
-  var setjmpId = 0;
-  var undef = 0;
-  var nan = global.NaN, inf = global.Infinity;
-  var tempInt = 0, tempBigInt = 0, tempBigIntS = 0, tempValue = 0, tempDouble = 0.0;
-  var tempRet0 = 0;
-
-  var __pthread_ptr = 0;
-  var __pthread_is_main_runtime_thread = 0;
-  var __pthread_is_main_browser_thread = 0;
-
-  var Math_floor=global.Math.floor;
-  var Math_abs=global.Math.abs;
-  var Math_sqrt=global.Math.sqrt;
-  var Math_pow=global.Math.pow;
-  var Math_cos=global.Math.cos;
-  var Math_sin=global.Math.sin;
-  var Math_tan=global.Math.tan;
-  var Math_acos=global.Math.acos;
-  var Math_asin=global.Math.asin;
-  var Math_atan=global.Math.atan;
-  var Math_atan2=global.Math.atan2;
-  var Math_exp=global.Math.exp;
-  var Math_log=global.Math.log;
-  var Math_ceil=global.Math.ceil;
-  var Math_imul=global.Math.imul;
-  var Math_min=global.Math.min;
-  var Math_max=global.Math.max;
-  var Math_clz32=global.Math.clz32;
-  var Math_fround=global.Math.fround;
-  var abort=env.abort;
-  var assert=env.assert;
-  var enlargeMemory=env.enlargeMemory;
-  var getTotalMemory=env.getTotalMemory;
-  var abortOnCannotGrowMemory=env.abortOnCannotGrowMemory;
-  var abortStackOverflow=env.abortStackOverflow;
-  var nullFunc_iiii=env.nullFunc_iiii;
-  var nullFunc_i=env.nullFunc_i;
-  var nullFunc_vi=env.nullFunc_vi;
-  var nullFunc_vii=env.nullFunc_vii;
-  var nullFunc_ii=env.nullFunc_ii;
-  var nullFunc_viii=env.nullFunc_viii;
-  var nullFunc_v=env.nullFunc_v;
-  var nullFunc_iii=env.nullFunc_iii;
-  var invoke_iiii=env.invoke_iiii;
-  var invoke_i=env.invoke_i;
-  var invoke_vi=env.invoke_vi;
-  var invoke_vii=env.invoke_vii;
-  var invoke_ii=env.invoke_ii;
-  var invoke_viii=env.invoke_viii;
-  var invoke_v=env.invoke_v;
-  var invoke_iii=env.invoke_iii;
-  var __spawn_thread=env.__spawn_thread;
-  var _putenv=env._putenv;
-  var _emscripten_get_now_is_monotonic=env._emscripten_get_now_is_monotonic;
-  var _fpathconf=env._fpathconf;
-  var ___unlock=env.___unlock;
-  var _emscripten_syscall=env._emscripten_syscall;
-  var ___assert_fail=env.___assert_fail;
-  var _utimes=env._utimes;
-  var ___buildEnvironment=env.___buildEnvironment;
-  var _emscripten_asm_const_i=env._emscripten_asm_const_i;
-  var _clock_gettime=env._clock_gettime;
-  var _emscripten_futex_wait=env._emscripten_futex_wait;
-  var _tzset=env._tzset;
-  var ___setErrNo=env.___setErrNo;
-  var _emscripten_set_current_thread_status_js=env._emscripten_set_current_thread_status_js;
-  var _pthread_getschedparam=env._pthread_getschedparam;
-  var _clearenv=env._clearenv;
-  var _emscripten_futex_wake=env._emscripten_futex_wake;
-  var _sysconf=env._sysconf;
-  var _utime=env._utime;
-  var ___call_main=env.___call_main;
-  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
-  var _confstr=env._confstr;
-  var _getenv=env._getenv;
-  var ___syscall54=env.___syscall54;
-  var _emscripten_has_threading_support=env._emscripten_has_threading_support;
-  var _pthread_create=env._pthread_create;
-  var _emscripten_get_now=env._emscripten_get_now;
-  var _chroot=env._chroot;
-  var ___lock=env.___lock;
-  var ___syscall6=env.___syscall6;
-  var _unsetenv=env._unsetenv;
-  var ___clock_gettime=env.___clock_gettime;
-  var _gettimeofday=env._gettimeofday;
-  var _atexit=env._atexit;
-  var ___syscall140=env.___syscall140;
-  var _emscripten_set_thread_name_js=env._emscripten_set_thread_name_js;
-  var _setenv=env._setenv;
-  var ___syscall146=env.___syscall146;
-  var _emscripten_conditional_set_current_thread_status_js=env._emscripten_conditional_set_current_thread_status_js;
-  var Atomics_load=global.Atomics.load;
-  var Atomics_store=global.Atomics.store;
-  var Atomics_exchange=global.Atomics.exchange;
-  var Atomics_compareExchange=global.Atomics.compareExchange;
-  var Atomics_add=global.Atomics.add;
-  var Atomics_sub=global.Atomics.sub;
-  var Atomics_and=global.Atomics.and;
-  var Atomics_or=global.Atomics.or;
-  var Atomics_xor=global.Atomics.xor;
-  var tempFloat = Math_fround(0);
-  const f0 = Math_fround(0);
-
-  function test() {
-   var $temp = 0;
-   $temp = (Atomics_load(HEAP32, 1229)|0);
-   $temp = (Atomics_load(HEAPU16, 1229)|0);
-   $temp = (Atomics_store(HEAP32, $temp>>2, 0)|0);
-   $temp = (Atomics_exchange(HEAP32, $temp>>2, 1)|0);
-   $temp = (Atomics_compareExchange(HEAP32, $temp>>2, 1, 2)|0);
-   $temp = (Atomics_add(HEAP32, $temp>>2, 0)|0);
-   $temp = (Atomics_sub(HEAP32, $temp>>2, 0)|0);
-   $temp = (Atomics_and(HEAP32, $temp>>2, 0)|0);
-   $temp = (Atomics_or(HEAP32, $temp>>2, 0)|0);
-   $temp = (Atomics_xor(HEAP32, $temp>>2, 0)|0);
-   $temp = (Atomics_xor(HEAPU32, 1024, 0)|0);
-   $temp = (Atomics_xor(HEAP16, 1024, 0)|0);
-   $temp = (Atomics_xor(HEAPU8, 1024, 0)|0);
-   // corner cases
-   $temp = (Atomics_compareExchange(HEAP8, $temp | 0, 1, 2)|0);
-   $temp = (Atomics_compareExchange(HEAP8, $temp >> 2, 1, 2)|0);
-  }
-
-  return { test: test };
-})
-;
diff --git a/binaryen/test/threads.wasm-only.asm.js b/binaryen/test/threads.wasm-only.asm.js
deleted file mode 100644
--- a/binaryen/test/threads.wasm-only.asm.js
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// Test wasm-only builds. In this case, fastcomp emits code that is
-// not asm.js, it will only ever run as wasm, and contains special intrinsics for
-// asm2wasm that map LLVM IR into i64s.
-//
-
-function asm(global, env, buffer) {
-  "use asm";
-
-  var HEAP8 = new global.Int8Array(buffer);
-  var HEAP16 = new global.Int16Array(buffer);
-  var HEAP32 = new global.Int32Array(buffer);
-  var HEAPU8 = new global.Uint8Array(buffer);
-  var HEAPU16 = new global.Uint16Array(buffer);
-  var HEAPU32 = new global.Uint32Array(buffer);
-  var HEAPF32 = new global.Float32Array(buffer);
-  var HEAPF64 = new global.Float64Array(buffer);
-
-  var STACKTOP = env.STACKTOP | 0;
-
-  var fround = global.Math.fround;
-  var Math_imul = global.Math.imul;
-
-  var illegalImport = env.illegalImport;
-  var illegalImportResult = env.illegalImportResult;
-
-  var _fabsf = env._fabsf;
-  var do_i64 = env.do_i64;
-  var abort = env.abort;
-
-  function test64() {
-    var x = i64(), y = i64(), z = 0; // define i64 variables using special intrinsic
-    var int32 = 0, float32 = fround(0), float64 = +0;
-    i64_atomics_store(4656, i64_const(92, 0))|0;
-    x = i64_atomics_load(4656);
-    y = i64_atomics_add(int32, i64_const(26, 0))|0;
-    x = i64_atomics_sub(1024, y)|0;
-    y = i64_atomics_and(1024, x)|0;
-    x = i64_atomics_or(1024, y)|0;
-    y = i64_atomics_xor(1024, x)|0;
-    x = i64_atomics_exchange(1024, y)|0;
-    y = i64_atomics_compareExchange(1024, x, y)|0;
-    return x;
-  }
-
-  return { test64: test64 };
-}
-
diff --git a/binaryen/test/try-body-multiple-insts.wasm b/binaryen/test/try-body-multiple-insts.wasm
deleted file mode 100644
Binary files a/binaryen/test/try-body-multiple-insts.wasm and /dev/null differ
diff --git a/binaryen/test/try-body-multiple-insts.wasm.fromBinary b/binaryen/test/try-body-multiple-insts.wasm.fromBinary
deleted file mode 100644
--- a/binaryen/test/try-body-multiple-insts.wasm.fromBinary
+++ /dev/null
@@ -1,26 +0,0 @@
-(module
- (type $none_=>_none (func))
- (func $0
-  (nop)
- )
- (func $1
-  (nop)
- )
- (func $2
-  (local $0 exnref)
-  (try
-   (do
-    (call $0)
-    (call $1)
-   )
-   (catch
-    (drop
-     (pop exnref)
-    )
-    (call $0)
-    (call $1)
-   )
-  )
- )
-)
-
diff --git a/binaryen/test/two_sides.asm.js b/binaryen/test/two_sides.asm.js
deleted file mode 100644
--- a/binaryen/test/two_sides.asm.js
+++ /dev/null
@@ -1,30 +0,0 @@
-Module["asm"] = (function(global, env, buffer) {
- "use asm";
- var Math_imul = global.Math.imul;
- function _test(i1, i2, i3, i4, i5) {
-  i1 = i1 | 0;
-  i2 = i2 | 0;
-  i3 = i3 | 0;
-  i4 = i4 | 0;
-  i5 = i5 | 0;
-  var d6 = 0.0;
-  if (!i5) {
-   d6 = +(Math_imul(i4, i3) | 0);
-   d6 = (+(i3 | 0) + d6) * (+(i4 | 0) + d6);
-   i5 = ~~d6;
-   return i5 | 0;
-  } else {
-   d6 = +(Math_imul(i2, i1) | 0);
-   d6 = (+(i3 | 0) + d6) * (d6 + +(i4 | 0));
-   i5 = ~~d6;
-   return i5 | 0;
-  }
-  return 0;
- }
- return {
-  _test: _test
- };
-});
-
-
-
diff --git a/binaryen/test/typed-function-references.wast b/binaryen/test/typed-function-references.wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/typed-function-references.wast
@@ -0,0 +1,44 @@
+(module
+  ;; inline ref type in result
+  (type $f64_=>_ref_null<_->_eqref> (func (param f64) (result (ref null (func (result eqref))))))
+  (type $=>eqref (func (result eqref)))
+
+  (type $i32-i32 (func (param i32) (result i32)))
+
+  (func $call-ref
+    (call_ref (ref.func $call-ref))
+  )
+  (func $return-call-ref
+    (return_call_ref (ref.func $call-ref))
+  )
+  (func $call-ref-more (param i32) (result i32)
+    (call_ref (i32.const 42) (ref.func $call-ref-more))
+  )
+  (func $call_from-param (param $f (ref $i32-i32)) (result i32)
+    (call_ref (i32.const 42) (local.get $f))
+  )
+  (func $call_from-param-null (param $f (ref null $i32-i32)) (result i32)
+    (call_ref (i32.const 42) (local.get $f))
+  )
+  (func $call_from-local-null (result i32)
+    (local $f (ref null $i32-i32))
+    (local.set $f (ref.func $call-ref-more))
+    (call_ref (i32.const 42) (local.get $f))
+  )
+  (func $ref-in-sig (param $0 f64) (result (ref null (func (result eqref))))
+    (ref.null $=>eqref)
+  )
+  (func $type-only-in-tuple-local
+    (local $x (i32 (ref null (func (result anyref))) f64))
+  )
+  (func $type-only-in-tuple-block
+    (drop
+      (block (result i32 (ref null (func (result anyref f32 anyref f32))) f64)
+        (unreachable)
+      )
+    )
+  )
+  (func $nested-type-only-there (result (ref (func (result (ref (func (param i32 i32 i32 i32 i32)))))))
+    (unreachable)
+  )
+)
diff --git a/binaryen/test/typed-function-references.wast.from-wast b/binaryen/test/typed-function-references.wast.from-wast
new file mode 100644
--- /dev/null
+++ b/binaryen/test/typed-function-references.wast.from-wast
@@ -0,0 +1,69 @@
+(module
+ (type $none_=>_none (func))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_eqref (func (result eqref)))
+ (type $i32_i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_anyref (func (result anyref)))
+ (type $none_=>_anyref_f32_anyref_f32 (func (result anyref f32 anyref f32)))
+ (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32)))
+ (type $none_=>_i32_ref?|none_->_anyref_f32_anyref_f32|_f64 (func (result i32 (ref null $none_=>_anyref_f32_anyref_f32) f64)))
+ (type $none_=>_ref?|i32_i32_i32_i32_i32_->_none| (func (result (ref null $i32_i32_i32_i32_i32_=>_none))))
+ (type $f64_=>_ref?|none_->_eqref| (func (param f64) (result (ref null $none_=>_eqref))))
+ (type $none_=>_ref?|none_->_ref?|i32_i32_i32_i32_i32_->_none|| (func (result (ref null $none_=>_ref?|i32_i32_i32_i32_i32_->_none|))))
+ (func $call-ref
+  (call_ref
+   (ref.func $call-ref)
+  )
+ )
+ (func $return-call-ref
+  (return_call_ref
+   (ref.func $call-ref)
+  )
+ )
+ (func $call-ref-more (param $0 i32) (result i32)
+  (call_ref
+   (i32.const 42)
+   (ref.func $call-ref-more)
+  )
+ )
+ (func $call_from-param (param $f (ref null $i32_=>_i32)) (result i32)
+  (call_ref
+   (i32.const 42)
+   (local.get $f)
+  )
+ )
+ (func $call_from-param-null (param $f (ref null $i32_=>_i32)) (result i32)
+  (call_ref
+   (i32.const 42)
+   (local.get $f)
+  )
+ )
+ (func $call_from-local-null (result i32)
+  (local $f (ref null $i32_=>_i32))
+  (local.set $f
+   (ref.func $call-ref-more)
+  )
+  (call_ref
+   (i32.const 42)
+   (local.get $f)
+  )
+ )
+ (func $ref-in-sig (param $0 f64) (result (ref null $none_=>_eqref))
+  (ref.null $none_=>_eqref)
+ )
+ (func $type-only-in-tuple-local
+  (local $x (i32 (ref null (func (result anyref))) f64))
+  (nop)
+ )
+ (func $type-only-in-tuple-block
+  (drop
+   (block $block (result i32 (ref null $none_=>_anyref_f32_anyref_f32) f64)
+    (unreachable)
+   )
+  )
+ )
+ (func $nested-type-only-there (result (ref null $none_=>_ref?|i32_i32_i32_i32_i32_->_none|))
+  (unreachable)
+ )
+)
diff --git a/binaryen/test/typed-function-references.wast.fromBinary b/binaryen/test/typed-function-references.wast.fromBinary
new file mode 100644
--- /dev/null
+++ b/binaryen/test/typed-function-references.wast.fromBinary
@@ -0,0 +1,100 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_anyref_f32_anyref_f32 (func (result anyref f32 anyref f32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_eqref (func (result eqref)))
+ (type $i32_i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_anyref (func (result anyref)))
+ (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32)))
+ (type $none_=>_i32_ref?|none_->_anyref_f32_anyref_f32|_f64 (func (result i32 (ref null $none_=>_anyref_f32_anyref_f32) f64)))
+ (type $none_=>_ref?|i32_i32_i32_i32_i32_->_none| (func (result (ref null $i32_i32_i32_i32_i32_=>_none))))
+ (type $f64_=>_ref?|none_->_eqref| (func (param f64) (result (ref null $none_=>_eqref))))
+ (type $none_=>_ref?|none_->_ref?|i32_i32_i32_i32_i32_->_none|| (func (result (ref null $none_=>_ref?|i32_i32_i32_i32_i32_->_none|))))
+ (func $call-ref
+  (call_ref
+   (ref.func $call-ref)
+  )
+ )
+ (func $return-call-ref
+  (return_call_ref
+   (ref.func $call-ref)
+  )
+ )
+ (func $call-ref-more (param $0 i32) (result i32)
+  (call_ref
+   (i32.const 42)
+   (ref.func $call-ref-more)
+  )
+ )
+ (func $call_from-param (param $f (ref null $i32_=>_i32)) (result i32)
+  (call_ref
+   (i32.const 42)
+   (local.get $f)
+  )
+ )
+ (func $call_from-param-null (param $f (ref null $i32_=>_i32)) (result i32)
+  (call_ref
+   (i32.const 42)
+   (local.get $f)
+  )
+ )
+ (func $call_from-local-null (result i32)
+  (local $f (ref null $i32_=>_i32))
+  (local.set $f
+   (ref.func $call-ref-more)
+  )
+  (call_ref
+   (i32.const 42)
+   (local.get $f)
+  )
+ )
+ (func $ref-in-sig (param $0 f64) (result (ref null $none_=>_eqref))
+  (ref.null $none_=>_eqref)
+ )
+ (func $type-only-in-tuple-local
+  (local $x i32)
+  (local $1 f64)
+  (local $2 (ref null $none_=>_anyref))
+  (nop)
+ )
+ (func $type-only-in-tuple-block
+  (local $0 (i32 (ref null (func (result anyref f32 anyref f32))) f64))
+  (local $1 (ref null $none_=>_anyref_f32_anyref_f32))
+  (local $2 i32)
+  (local.set $0
+   (block $label$1 (result i32 (ref null $none_=>_anyref_f32_anyref_f32) f64)
+    (unreachable)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $2
+     (tuple.extract 0
+      (local.get $0)
+     )
+    )
+    (drop
+     (block (result (ref null $none_=>_anyref_f32_anyref_f32))
+      (local.set $1
+       (tuple.extract 1
+        (local.get $0)
+       )
+      )
+      (drop
+       (tuple.extract 2
+        (local.get $0)
+       )
+      )
+      (local.get $1)
+     )
+    )
+    (local.get $2)
+   )
+  )
+ )
+ (func $nested-type-only-there (result (ref null $none_=>_ref?|i32_i32_i32_i32_i32_->_none|))
+  (unreachable)
+ )
+)
+
diff --git a/binaryen/test/typed-function-references.wast.fromBinary.noDebugInfo b/binaryen/test/typed-function-references.wast.fromBinary.noDebugInfo
new file mode 100644
--- /dev/null
+++ b/binaryen/test/typed-function-references.wast.fromBinary.noDebugInfo
@@ -0,0 +1,100 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_anyref_f32_anyref_f32 (func (result anyref f32 anyref f32)))
+ (type $i32_=>_i32 (func (param i32) (result i32)))
+ (type $none_=>_eqref (func (result eqref)))
+ (type $i32_i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32 i32)))
+ (type $none_=>_i32 (func (result i32)))
+ (type $none_=>_anyref (func (result anyref)))
+ (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32)))
+ (type $none_=>_i32_ref?|none_->_anyref_f32_anyref_f32|_f64 (func (result i32 (ref null $none_=>_anyref_f32_anyref_f32) f64)))
+ (type $none_=>_ref?|i32_i32_i32_i32_i32_->_none| (func (result (ref null $i32_i32_i32_i32_i32_=>_none))))
+ (type $f64_=>_ref?|none_->_eqref| (func (param f64) (result (ref null $none_=>_eqref))))
+ (type $none_=>_ref?|none_->_ref?|i32_i32_i32_i32_i32_->_none|| (func (result (ref null $none_=>_ref?|i32_i32_i32_i32_i32_->_none|))))
+ (func $0
+  (call_ref
+   (ref.func $0)
+  )
+ )
+ (func $1
+  (return_call_ref
+   (ref.func $0)
+  )
+ )
+ (func $2 (param $0 i32) (result i32)
+  (call_ref
+   (i32.const 42)
+   (ref.func $2)
+  )
+ )
+ (func $3 (param $0 (ref null $i32_=>_i32)) (result i32)
+  (call_ref
+   (i32.const 42)
+   (local.get $0)
+  )
+ )
+ (func $4 (param $0 (ref null $i32_=>_i32)) (result i32)
+  (call_ref
+   (i32.const 42)
+   (local.get $0)
+  )
+ )
+ (func $5 (result i32)
+  (local $0 (ref null $i32_=>_i32))
+  (local.set $0
+   (ref.func $2)
+  )
+  (call_ref
+   (i32.const 42)
+   (local.get $0)
+  )
+ )
+ (func $6 (param $0 f64) (result (ref null $none_=>_eqref))
+  (ref.null $none_=>_eqref)
+ )
+ (func $7
+  (local $0 i32)
+  (local $1 f64)
+  (local $2 (ref null $none_=>_anyref))
+  (nop)
+ )
+ (func $8
+  (local $0 (i32 (ref null (func (result anyref f32 anyref f32))) f64))
+  (local $1 (ref null $none_=>_anyref_f32_anyref_f32))
+  (local $2 i32)
+  (local.set $0
+   (block $label$1 (result i32 (ref null $none_=>_anyref_f32_anyref_f32) f64)
+    (unreachable)
+   )
+  )
+  (drop
+   (block (result i32)
+    (local.set $2
+     (tuple.extract 0
+      (local.get $0)
+     )
+    )
+    (drop
+     (block (result (ref null $none_=>_anyref_f32_anyref_f32))
+      (local.set $1
+       (tuple.extract 1
+        (local.get $0)
+       )
+      )
+      (drop
+       (tuple.extract 2
+        (local.get $0)
+       )
+      )
+      (local.get $1)
+     )
+    )
+    (local.get $2)
+   )
+  )
+ )
+ (func $9 (result (ref null $none_=>_ref?|i32_i32_i32_i32_i32_->_none|))
+  (unreachable)
+ )
+)
+
diff --git a/binaryen/test/unit.asm.js b/binaryen/test/unit.asm.js
deleted file mode 100644
--- a/binaryen/test/unit.asm.js
+++ /dev/null
@@ -1,811 +0,0 @@
-function asm(global, env, buffer) {
-  "use asm";
-
-  var t = global.NaN, u = global.Infinity;
-  var Int = 0;
-  var Double = 0.0;
-  var Math_fround = global.Math.fround;
-  var Math_abs = global.Math.abs;
-  var Math_ceil = global.Math.ceil;
-  var Math_max = global.Math.max;
-  var Math_min = global.Math.min;
-  var Math_sqrt = global.Math.sqrt;
-  var tempDoublePtr = env.tempDoublePtr | 0;
-  var n = env.gb | 0;
-  var STACKTOP = env.STACKTOP | 0;
-  var setTempRet0=env.setTempRet0;
-
-  var abort = env.abort;
-  var print = env.print;
-  var h = env.h;
-  var return_int = env.return_int;
-  var emscripten_log = env.emscripten_log;
-
-  var HEAP8 = new global.Int8Array(buffer);
-  var HEAP16 = new global.Int16Array(buffer);
-  var HEAP32 = new global.Int32Array(buffer);
-  var HEAPU8 = new global.Uint8Array(buffer);
-  var HEAPU16 = new global.Uint16Array(buffer);
-  var HEAPU32 = new global.Uint32Array(buffer);
-  var HEAPF32 = new global.Float32Array(buffer);
-  var HEAPF64 = new global.Float64Array(buffer);
-
-  var nonZero = 1337;
-
-  function big_negative() {
-    var temp = 0.0;
-    temp = +-2147483648;
-    temp = -2147483648.0;
-    temp = -21474836480.0;
-    temp = 0.039625;
-    temp = -0.039625;
-  }
-  function importedDoubles() {
-    var temp = 0.0;
-    temp = t + u + (-u) + (-t);
-    if ((Int | 0) > 0) return -3.4;
-    if (Double > 0.0) return 5.6;
-    return 1.2;
-  }
-  function doubleCompares(x, y) {
-    x = +x;
-    y = +y;
-    var t = 0.0;
-    var Int = 0.0, Double = 0; // confusing with globals
-    if (x > 0.0) return 1.2;
-    Int = x;
-    Double = n;
-    if (Int > 0.0) return -3.4;
-    if ((Double|0) > 0) return 5.6;
-    if (x < y) return +x;
-    return +y;
-  }
-  function intOps(x) {
-    x = x | 0;
-    return (!x) | 0;
-  }
-  function hexLiterals() {
-    var i = 0;
-    i = 0x0 + 0x12ABCdef + 0xFEDcba90 | 0;
-  }
-  function conversions(i, d, f) {
-    i = i | 0;
-    d = +d;
-    f = Math_fround(f);
-    i = ~~d;
-    i = ~~f;
-    d = +(i | 0);
-    d = +(i >>> 0);
-  }
-  function seq() {
-    var J = 0.0;
-    J = (0.1, 5.1) - (3.2, 4.2);
-  }
-  function switcher(x) {
-    x = x | 0;
-    var waka = 0;
-    switch (x | 0) {
-      case 1: return 1;
-      case 2: return 2;
-    }
-    switch (x | 0) {
-      case 12: return 121;
-      case 5: return 51;
-    }
-    Lout: switch (x | 0) {
-      case 12: break;
-      case 10: break Lout;
-      case 5: {
-        while (1) {
-          break;
-        }
-        break;
-      }
-      case 2: {
-        while (1) {
-          break Lout;
-        }
-        break;
-      }
-    }
-
-    L1 : while (1) {
-     L3 : while (1) switch (x | 0) {
-     case -1:
-      {
-       break L1;
-       break;
-      }
-     case 116:
-      {
-       waka = 1;
-       break;
-      }
-     case 110:
-      {
-       break L3;
-       break;
-      }
-     default:
-      {
-       break L1;
-      }
-     }
-     h(120);
-    }
-
-    return 0;
-  }
-  function blocker() {
-    L: {
-      break L;
-    }
-  }
-  function frem() {
-    return +(5.5 % 1.2);
-  }
-  function frem_float() {
-    return Math_fround(Math_fround(5.5) % Math_fround(1.2));
-  }
-  function big_uint_div_u() {
-    var x = 0;
-    x = (4294967295 / 2)&-1;
-    return x | 0;
-  }
-  function trapping_sint_div_s() {
-    var x = 0;
-    x = (-2147483648 / -1);
-    return x | 0;
-  }
-  function fr(x) {
-    x = Math_fround(x);
-    var y = Math_fround(0), z = 0.0;
-    Math_fround(z);
-    Math_fround(y);
-    Math_fround(5);
-    Math_fround(0);
-    Math_fround(5.0);
-    Math_fround(0.0);
-  }
-  function negZero() {
-    return +-0;
-  }
-  function abs() {
-    var x = 0, y = 0.0, z = Math_fround(0);
-    x = Math_abs(0) | 0;
-    y = +Math_abs(0.0);
-    z = Math_fround(Math_abs(Math_fround(0)));
-  }
-  function minmax() {
-    var x = 0.0, y = 0.0, z = Math_fround(0), w = Math_fround(0);
-    x = +Math_min(+x, +y);
-    y = +Math_max(+x, +y);
-    z = Math_fround(Math_min(Math_fround(z), Math_fround(w)));
-    w = Math_fround(Math_max(Math_fround(z), Math_fround(w)));
-  }
-  function neg() {
-    var x = Math_fround(0);
-    x = Math_fround(-x);
-    FUNCTION_TABLE_c[1 & 7](x);
-  }
-  function cneg(x) {
-    x = Math_fround(x);
-    FUNCTION_TABLE_c[1 & 7](x);
-  }
-  function ___syscall_ret() {
-   var $0 = 0;
-   ($0>>>0) > 4294963200; // -4096
-  }
-  function smallCompare(i, j) {
-    i = i | 0;
-    j = j | 0;
-    if ((i | 0) < (j | 0)) i = i + 1 | 0;
-    if ((i >>> 0) < (j >>> 0)) i = i + 1 | 0;
-    return i | 0;
-  }
-  function cneg_nosemicolon() {
-    FUNCTION_TABLE_vi[1 & 7](1) // no semicolon
-  }
-  function forLoop() {
-    var i = 0;
-    for (i = 1; (i | 0) < 200; i = i + 1 | 0) {
-      h(i | 0);
-    }
-  }
-  function ceiling_32_64(u, B) {
-    u = Math_fround(u);
-    B = +B;
-    var temp = Math_fround(0);
-    temp = Math_fround(Math_ceil(B));
-    temp = Math_fround(u * Math_fround(Math_ceil(Math_fround(B))));
-  }
-  function aborts() {
-    abort();
-    abort(55);
-    abort();
-    abort(12.34);
-    abort(+Math_fround(56.78));
-  }
-  function continues() {
-    while (1) {
-      print(1);
-      do {
-        print(5);
-        if (return_int() | 0) continue;
-      } while (0);
-      print(2);
-    }
-  }
-  function bitcasts(i, f) {
-    i = i | 0;
-    f = Math_fround(f);
-    var d = 0.0;
-    (HEAP32[tempDoublePtr >> 2] = i, Math_fround(HEAPF32[tempDoublePtr >> 2])); // i32->f32
-    (HEAP32[tempDoublePtr >> 2] = i, +HEAPF32[tempDoublePtr >> 2]); // i32->f32, no fround
-    (HEAPF32[tempDoublePtr >> 2] = f, HEAP32[tempDoublePtr >> 2] | 0); // f32->i32
-    (HEAPF32[tempDoublePtr >> 2] = d, HEAP32[tempDoublePtr >> 2] | 0); // f64 with implict f32 conversion, ->i32
-  }
-  function recursiveBlockMerging(x) {
-    x = x | 0;
-    lb((1, x) + (2, 3) + (((4, 5), 6), 7) + (8, (9, (10, (11, 12)))) | 0) | 0;
-    x = (lb(1) | 0, x) + (lb(2) | 0, lb(3) | 0) + (((lb(4) | 0, lb(5) | 0), lb(6) | 0), lb(7) | 0) + (lb(8) | 0, (lb(9) | 0, (lb(10) | 0, (lb(11) | 0, lb(12) | 0)))) | 0;
-    return x | 0;
-  }
-
-  function lb(a) {
-   a = a | 0;
-   HEAP32[a >> 2] = n + 136 + 8;
-   return 0;
-  }
-
-  function forgetMe() {
-    123.456;
-  }
-  function exportMe() {
-    -3.14159;
-  }
-
-  function zeroInit(x) {
-    x = x | 0;
-    var y = 0; // reusing this with x is dangerous - x has a value, and y needs to start at 0!
-    if (lb(0) | 0) {
-      if (lb(1) | 0) y = 3;
-    } else {
-      y = 3;
-    }
-    if ((y | 0) == 3) {
-      lb(2) | 0;
-    }
-  }
-
-  function phi() {
-    var x = 0;
-    do {
-      if (lb(1) | 0) {
-        x = 0;
-        break;
-      }
-      x = 1;
-    } while (0);
-    return x | 0;
-  }
-
-  function smallIf() {
-    do {
-      if (return_int() | 0) {
-        lb(3) | 0;
-      } else {
-        break;
-      }
-    } while (0);
-  }
-
-  function dropCall() {
-    if (return_int() | 0) {
-      phi() | 0; // drop this
-      setTempRet0(10); // this too
-      zeroInit(setTempRet0(10) | 0);
-    }
-    return phi() | 0;
-  }
-
-  function useGlobalSet() {
-    var x = 0;
-    x = (Int = 10);
-    Int = 20;
-    return (Int = 30) | 0;
-  }
-
-  function usesGlobalSet2() {
-    return (Int = 40, 50) | 0;
-  }
-
-  function breakThroughMany($s) {
-   $s = $s|0;
-   L1: do {
-    if ($s) {
-     while(1) {
-      if (!($s)) {
-       break L1;
-      }
-      zeroInit(0);
-     }
-    } else {
-     1337;
-    }
-   } while(0);
-  }
-
-  function ifChainEmpty(label) {
-    label = label | 0;
-    if ((label|0) == 4) {
-      return 0;
-    }
-    else if ((label|0) == 7) {
-      // unreachable;
-    }
-    return 0;
-  }
-
-  function heap8NoShift(x) {
-    x = x | 0;
-    return HEAP8[x | 0] | 0;
-  }
-
-  function conditionalTypeFun() {
-    var x = 0, y = 0.0;
-    x = return_int() | 0 ? abort(5) | 0 : 2;
-    y = return_int() | 0 ? +abort(7) : 4.5;
-  }
-
-  function loadSigned(x) {
-    x = x | 0;
-    loadSigned(HEAP8[x >> 0] << 24 >> 24);
-    loadSigned(HEAPU8[x >> 0] << 24 >> 24);
-    loadSigned(HEAP16[x >> 1] << 16 >> 16);
-    loadSigned(HEAPU16[x >> 1] << 16 >> 16);
-    loadSigned(HEAP8[x >> 0] << 24 >> 16);
-    loadSigned(HEAPU8[x >> 0] << 16 >> 24);
-    loadSigned(HEAP16[x >> 1] << 16 >> 24);
-    loadSigned(HEAPU16[x >> 1] << 24 >> 16);
-  }
-
-  function z(x) {
-    x = Math_fround(x);
-  }
-  function w() {
-    return 0.0;
-  }
-
-  function globalOpts() {
-    var x = 0, y = 0.0;
-    x = Int;
-    y = Double;
-    HEAP8[13] = HEAP32[3]; // access memory, should not confuse the global writes
-    Double = y;
-    Int = x;
-    globalOpts();
-    x = Int;
-    if (return_int() | 0) Int = 20; // but this does interfere
-    Int = x;
-    globalOpts();
-    x = Int;
-    globalOpts(); // this too
-    Int = x;
-  }
-
-  function dropCallImport() {
-    if (return_int() | 0) return_int() | 0;
-  }
-
-  function loophi(x, y) {
-   x = x | 0;
-   y = y | 0;
-   var temp = 0, inc = 0, loopvar = 0; // this order matters
-   loopvar = x;
-   while(1) {
-    loophi(loopvar | 0, 0);
-    temp = loopvar;
-    if (temp) {
-     if (temp) {
-      break;
-     }
-    }
-    inc = loopvar + 1 | 0;
-    if ((inc|0) == (y|0)) {
-     loopvar = inc;
-    } else {
-     break;
-    }
-   }
-  }
-
-  function loophi2() {
-   var jnc = 0, i = 0, i$lcssa = 0, temp = 0, j = 0;
-   i = 0;
-   L7: while(1) {
-    j = 0;
-    while(1) {
-     temp = j;
-     if (return_int() | 0) {
-      if (temp) {
-       i$lcssa = i;
-       break L7;
-      }
-     }
-     jnc = j + 1 | 0;
-     if (jnc) {
-      j = jnc;
-     } else {
-      break;
-     }
-    }
-   }
-   return i$lcssa | 0
-  }
-
-  function loophi2b() {
-   var jnc = 0, i = 0, i$lcssa = 0, temp = 0, j = 0;
-   i = 0;
-   L7: while(1) {
-    j = 0;
-    while(1) {
-     temp = j;
-     if (return_int() | 0) {
-      if (temp) {
-       i$lcssa = j;
-       break L7;
-      }
-     }
-     jnc = j + 1 | 0;
-     if (jnc) {
-      j = jnc;
-     } else {
-      break;
-     }
-    }
-   }
-   return i$lcssa | 0
-  }
-
-  function relooperJumpThreading(x) {
-   x = x | 0;
-   var label = 0;
-   // from if
-   if (x) {
-    h(0);
-    label = 1;
-   }
-   if ((label|0) == 1) {
-    h(1);
-   }
-   h(-1);
-   // from loop
-   while (1) {
-    x = x + 1 | 0;
-    if (x) {
-     h(2);
-     label = 2;
-     break;
-    }
-   }
-   if ((label|0) == 2) {
-    h(3);
-   }
-   h(-2);
-   // if-else afterward
-   if (x) {
-    h(4);
-    if ((x|0) == 3) {
-     label = 3;
-    } else {
-     label = 4;
-    }
-   }
-   if ((label|0) == 3) {
-    h(5);
-   } else if ((label|0) == 4) {
-    h(6);
-   }
-   h(-3);
-   // two ifs afterward
-   if (x) {
-    h(7);
-    if ((x|0) == 5) {
-     label = 5;
-    } else {
-     label = 6;
-    }
-   }
-   if ((label|0) == 5) {
-    h(8);
-    if ((x|0) == 6) {
-     label = 6;
-    }
-   }
-   if ((label|0) == 6) {
-    h(9);
-   }
-   h(-4);
-   // labeled if after
-   if (x) {
-    h(10);
-    label = 7;
-   }
-   L1: do {
-    if ((label|0) == 7) {
-     h(11);
-     break L1;
-    }
-   } while (0);
-   h(-5);
-   // labeled if after normal if
-   if (x) {
-    h(12);
-    if ((x|0) == 8) {
-      label = 8;
-    } else {
-      label = 9;
-    }
-   }
-   if ((label|0) == 8) {
-    h(13);
-    if (x) label = 9;
-   }
-   L1: do {
-    if ((label|0) == 9) {
-     h(14);
-     break L1;
-    }
-   } while (0);
-   h(-6);
-   // TODO
-   // labeled if after a first if
-   // do-enclosed if after (?)
-   // test multiple labels, some should be ignored initially by JumpUpdater
-   return x | 0;
-  }
-
-  function relooperJumpThreading__ZN4game14preloadweaponsEv($12, $14, $or$cond8, $or$cond6, $vararg_ptr5, $11, $exitcond) {
-   $12 = $12 | 0;
-   $14 = $14 | 0;
-   $or$cond8 = $or$cond8 | 0;
-   $or$cond6 = $or$cond6 | 0;
-   $vararg_ptr5 = $vararg_ptr5 | 0;
-   $11 = $11 | 0;
-   $exitcond = $exitcond | 0;
-   var label = 0;
-   while(1) {
-    if ($14) {
-     if ($or$cond8) {
-      label = 7;
-     } else {
-      label = 8;
-     }
-    } else {
-     if ($or$cond6) {
-      label = 7;
-     } else {
-      label = 8;
-     }
-    }
-    if ((label|0) == 7) {
-     label = 0;
-    }
-    else if ((label|0) == 8) {
-     label = 0;
-     HEAP32[$vararg_ptr5>>2] = $11;
-    }
-   }
-  }
-
-  function relooperJumpThreading_irreducible(x) {
-   x = x | 0;
-   var label = 0;
-   if ((x|0) == 100) {
-    label = 1;
-   } else {
-    label = 10;
-   }
-   if ((label|0) == 1) {
-    while (1) {
-     relooperJumpThreading_irreducible(1337);
-     label = 1; // this is ok - the if means the body of the if begins with the block for 1. so a setting inside the body of the if must return to the top of the if
-    }
-   }
-   // too many settings, we just look one back, so this one will not be optimized
-   if ((x|0) == 200) {
-    label = 2;
-   } else {
-    label = 10;
-   }
-   if ((x|0) == 300) {
-    label = 2;
-   }
-   if ((label|0) == 2) {
-    relooperJumpThreading_irreducible(1448);
-   }
-   if ((label|0) == 10) {
-    relooperJumpThreading_irreducible(2000);
-   }
-  }
-
-  function __Z12multi_varargiz($0, $$06$i4, $exitcond$i6, $2) {
-   $0 = $0|0;
-   $$06$i4 = $$06$i4 | 0;
-   $exitcond$i6 = $exitcond$i6 | 0;
-   $2 = $2 | 0;
-   var $12 = 0, $20 = 0;
-   if ($2) {
-    while(1) {
-     $12 = $$06$i4;
-     if ($exitcond$i6) {
-      break;
-     } else {
-      $$06$i4 = $20;
-     }
-    }
-   } else {
-    lb(1) | 0; // returns a value, and the while is unreachable
-   }
-  }
-
-  function jumpThreadDrop() {
-    var label = 0, temp = 0;
-    temp = return_int() | 0;
-    while (1) {
-      label = 14;
-      break;
-    }
-    if ((label | 0) == 10) {
-    } else if ((label | 0) == 12) {
-      return_int() | 0; // drop in the middle of an if-else chain for threading
-    } else if ((label | 0) == 14) {
-    }
-    return temp | 0;
-  }
-
-  function dropIgnoredImportInIf($0,$1,$2) {
-   $0 = $0|0;
-   $1 = $1|0;
-   $2 = $2|0;
-   do {
-    if ($0) {
-     $0 = 1;
-     lb($2 | 0) | 0;
-    } else {
-     break;
-    }
-   } while(0);
-   return;
-  }
-
-  function big_fround() {
-    return Math_fround(4294967295);
-  }
-
-  function dropIgnoredImportsInIf($0,$1,$2) {
-   $0 = $0|0;
-   $1 = $1|0;
-   $2 = $2|0;
-   do {
-    if ($0) {
-     lb($1 | 0) | 0;
-    } else {
-     lb($2 | 0) | 0;
-    }
-   } while(0);
-   return;
-  }
-
-  function f32_ucast(x) {
-    x = x | 0;
-    return Math_fround(x>>>0);
-  }
-  function f32_scast(x) {
-    x = x | 0;
-    return Math_fround(x|0);
-  }
-
-  function store_fround(x) {
-    x = x | 0;
-    HEAPF64[10] = Math_fround(x|0);
-  }
-
-  function relocatableAndModules() {
-    ftCall_v(10); // function table call
-    mftCall_v(20); // possible inter-module function table call
-    return ftCall_idi(30, 1.5, 200) | 0; // with args
-  }
-
-  function exported_f32_user(x, y, z) {
-    x = x | 0;
-    y = Math_fround(y);
-    z = +z;
-    return Math_fround(y);
-  }
-
-  function sqrts(x) {
-    x = +x;
-    return +(+Math_sqrt(x) + +Math_fround(Math_sqrt(Math_fround(x))));
-  }
-
-  function f2u(x) {
-    x = +x;
-    return (~~x>>>0) | 0;
-  }
-  function f2s(x) {
-    x = +x;
-    return (~~x) | 0;
-  }
-
-  function autoDrop(x) {
-    x = x | 0;
-    while (1) {
-      if ((x | 0) == 17) {
-        return 5;
-        autoDrop(1) | 0;
-      } else {
-        break;
-        x = autoDrop(2) | 0;
-      }
-    }
-    return x | 0;
-  }
-
-  function indirectInSequence() {
-   var i1 = 0;
-   // this indirect call should have the right type, vi
-   i1 = (FUNCTION_TABLE_vi[1 & 7](0), 1);
-  }
-
-  function emterpretify_assertions_safeHeap() {
-   var i1 = 0;
-    // assignment into the function table param, optimizer can do things there
-   FUNCTION_TABLE_vi[(Int = 1) & 7](i1 | 0);
-  }
-
-  function call_emscripten_log() {
-    // emscripten_log has no return value, don't let the conditional after the comma confuse you
-    emscripten_log(), 2 ? abort() | 0 : 3;
-  }
-
-  function mod_detectSign(d1, d2, d8) {
-    d1 = +d1;
-    d2 = +d2;
-    d8 = +d8;
-    return ~~(d2 - d8 % d1 / d1 * d2);
-  }
-
-  function keepAlive() {
-    sqrts(3.14159);
-    sqrts(2.18281); // don't inline it either
-    f2u(100.0);
-    f2s(100.0);
-    autoDrop(52) | 0;
-    indirectInSequence();
-    emterpretify_assertions_safeHeap();
-    call_emscripten_log();
-    mod_detectSign(1.0, 2.31, 9.78);
-    nonZero = nonZero + 1 | 0;
-  }
-
-  function v() {
-  }
-  function vi(x) {
-    x = x | 0;
-  }
-  function ii(x) {
-    x = x | 0;
-    return x | 0;
-  }
-
-  var FUNCTION_TABLE_a = [ v, big_negative, v, v ];
-  var FUNCTION_TABLE_b = [ w, w, importedDoubles, w ];
-  var FUNCTION_TABLE_c = [ z, cneg, z, z, z, z, z, z ];
-  var FUNCTION_TABLE_vi = [ vi, vi, vi, vi, vi, vi, vi, vi ];
-  var FUNCTION_TABLE_ii = [ ii ];
-
-  return { big_negative: big_negative, pick: forgetMe, pick: exportMe, doubleCompares: doubleCompares, intOps: intOps, conversions: conversions, switcher: switcher, frem: frem, frem_float: frem_float, big_uint_div_u: big_uint_div_u, trapping_sint_div_s: trapping_sint_div_s, fr: fr, negZero: negZero, neg: neg, smallCompare: smallCompare, cneg_nosemicolon: cneg_nosemicolon, forLoop: forLoop, ceiling_32_64: ceiling_32_64, aborts: aborts, continues: continues, bitcasts: bitcasts, recursiveBlockMerging: recursiveBlockMerging, lb: lb, zeroInit: zeroInit, phi: phi, smallIf: smallIf, dropCall: dropCall, useGlobalSet: useGlobalSet, usesGlobalSet2: usesGlobalSet2, breakThroughMany: breakThroughMany, ifChainEmpty: ifChainEmpty, heap8NoShift: heap8NoShift, conditionalTypeFun: conditionalTypeFun, loadSigned: loadSigned, globalOpts: globalOpts, dropCallImport: dropCallImport, loophi: loophi, loophi2: loophi2, loophi2b: loophi2b, relooperJumpThreading: relooperJumpThreading, relooperJumpThreading__ZN4game14preloadweaponsEv: relooperJumpThreading__ZN4game14preloadweaponsEv, __Z12multi_varargiz: __Z12multi_varargiz, jumpThreadDrop: jumpThreadDrop, dropIgnoredImportInIf: dropIgnoredImportInIf, dropIgnoredImportsInIf: dropIgnoredImportsInIf, relooperJumpThreading_irreducible: relooperJumpThreading_irreducible, store_fround: store_fround, exportedNumber: 42, relocatableAndModules: relocatableAndModules, exported_f32_user: exported_f32_user, keepAlive: keepAlive };
-}
-
diff --git a/binaryen/test/unit/input/hello_world.wat b/binaryen/test/unit/input/hello_world.wat
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/hello_world.wat
@@ -0,0 +1,11 @@
+(module
+ (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
+ (memory $0 256 256)
+ (export "add" (func $add))
+ (func $add (param $x i32) (param $y i32) (result i32)
+  (i32.add
+   (local.get $x)
+   (local.get $y)
+  )
+ )
+)
diff --git a/binaryen/test/unit/input/random_data.txt b/binaryen/test/unit/input/random_data.txt
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/input/random_data.txt
@@ -0,0 +1,1 @@
+6sgkjdfghk34589n-947-vn98f2yr-nb8f7t08b7gv*~&!%&^@}{PASD kjgsdf768
diff --git a/binaryen/test/unit/test_errors.py b/binaryen/test/unit/test_errors.py
deleted file mode 100644
--- a/binaryen/test/unit/test_errors.py
+++ /dev/null
@@ -1,40 +0,0 @@
-import os
-
-from scripts.test import shared
-from . import utils
-
-
-class ErrorsTest(utils.BinaryenTestCase):
-    def test_parsing_error_msg(self):
-        module = '''
-(module
-  (func $foo
-    (abc)
-  )
-)
-'''
-        p = shared.run_process(shared.WASM_OPT + ['--print', '-o', os.devnull],
-                               input=module, check=False, capture_output=True)
-        self.assertNotEqual(p.returncode, 0)
-        self.assertIn("parse exception: abc (at 4:4)", p.stderr)
-
-    def test_validation_error_msg(self):
-        def test(args=[], extra_expected=None):
-            module = '''
-(module
-  (memory (shared 10 20))
-)
-'''
-            p = shared.run_process(shared.WASM_OPT + ['-o', os.devnull] + args,
-                                   input=module, check=False, capture_output=True)
-            self.assertNotEqual(p.returncode, 0)
-            self.assertIn('memory is shared, but atomics are disabled', p.stderr)
-            if extra_expected:
-                self.assertIn(extra_expected, p.stdout)
-
-        test()
-        # when the user asks to print the module, we print it even if it is
-        # invalid, for debugging (otherwise, an invalid module would not reach
-        # the stage of runnning passes, and print is a pass, so nothing would
-        # be printed)
-        test(['--print'], '(module')
diff --git a/binaryen/test/unit/test_features.py b/binaryen/test/unit/test_features.py
--- a/binaryen/test/unit/test_features.py
+++ b/binaryen/test/unit/test_features.py
@@ -153,7 +153,7 @@
          )
         )
         '''
-        self.check_tail_call(module, 'return_call requires tail calls to be enabled')
+        self.check_tail_call(module, 'return_call* requires tail calls to be enabled')
 
     def test_tail_call_indirect(self):
         module = '''
@@ -167,7 +167,7 @@
          )
         )
         '''
-        self.check_tail_call(module, 'return_call_indirect requires tail calls to be enabled')
+        self.check_tail_call(module, 'return_call* requires tail calls to be enabled')
 
     def test_reference_types_externref(self):
         module = '''
@@ -408,5 +408,6 @@
             '--enable-reference-types',
             '--enable-multivalue',
             '--enable-gc',
-            '--enable-memory64'
+            '--enable-memory64',
+            '--enable-typed-function-references',
         ], p2.stdout.splitlines())
diff --git a/binaryen/test/unit/test_initial_fuzz.py b/binaryen/test/unit/test_initial_fuzz.py
new file mode 100644
--- /dev/null
+++ b/binaryen/test/unit/test_initial_fuzz.py
@@ -0,0 +1,35 @@
+import subprocess
+from scripts.test import shared
+from . import utils
+
+
+class InitialFuzzTest(utils.BinaryenTestCase):
+    def test_empty_initial(self):
+        # generate fuzz from random data
+        data = self.input_path('random_data.txt')
+        a = shared.run_process(shared.WASM_OPT + ['-ttf', '--print', data],
+                               stdout=subprocess.PIPE).stdout
+
+        # generate fuzz from random data with initial empty wasm
+        empty_wasm = self.input_path('empty.wasm')
+        b = shared.run_process(
+            shared.WASM_OPT + ['-ttf', '--print', data,
+                               '--initial-fuzz=' + empty_wasm],
+            stdout=subprocess.PIPE).stdout
+
+        # an empty initial wasm causes no changes
+        self.assertEqual(a, b)
+
+    def test_small_initial(self):
+        data = self.input_path('random_data.txt')
+        hello_wat = self.input_path('hello_world.wat')
+        out = shared.run_process(shared.WASM_OPT + ['-ttf', '--print', data,
+                                 '--initial-fuzz=' + hello_wat],
+                                 stdout=subprocess.PIPE).stdout
+
+        # the function should be there (perhaps with modified contents - don't
+        # check that)
+        self.assertIn('(export "add" (func $add))', out)
+
+        # there should be other fuzz contents added as well
+        self.assertGreater(out.count('(export '), 1)
diff --git a/binaryen/test/unit/test_memory_packing.py b/binaryen/test/unit/test_memory_packing.py
--- a/binaryen/test/unit/test_memory_packing.py
+++ b/binaryen/test/unit/test_memory_packing.py
@@ -13,7 +13,7 @@
         module = '''
         (module
          (memory 256 256)
-         (data (i32.const 0) %s)
+         (data $d (i32.const 0) %s)
         )
         ''' % data
         opts = ['--memory-packing', '--disable-bulk-memory', '--print',
@@ -21,9 +21,10 @@
         p = shared.run_process(shared.WASM_OPT + opts, input=module,
                                check=False, capture_output=True)
         output = [
-            '(data (i32.const 999970) "A")',
-            '(data (i32.const 999980) "A")',
-            '(data (i32.const 999990) "A' + ('\\00' * 9) + 'A")'
+            '(data $d (i32.const 0) "A")',
+            '(data $d.1 (i32.const 10) "A")',
+            '(data $d.99998 (i32.const 999980) "A")',
+            '(data $d.99999 (i32.const 999990) "A' + ('\\00' * 9) + 'A")'
         ]
         self.assertEqual(p.returncode, 0)
         for line in output:
diff --git a/binaryen/test/unit/test_tail_call_type.py b/binaryen/test/unit/test_tail_call_type.py
--- a/binaryen/test/unit/test_tail_call_type.py
+++ b/binaryen/test/unit/test_tail_call_type.py
@@ -21,7 +21,7 @@
                                input=module, check=False, capture_output=True)
         self.assertNotEqual(p.returncode, 0)
         self.assertIn(
-            'return_call callee return type must match caller return type',
+            'return_call* callee return type must match caller return type',
             p.stderr)
 
     def test_return_call_indirect(self):
@@ -41,5 +41,5 @@
                                input=module, check=False, capture_output=True)
         self.assertNotEqual(p.returncode, 0)
         self.assertIn(
-            'return_call_indirect callee return type must match caller return type',
+            'return_call* callee return type must match caller return type',
             p.stderr)
diff --git a/binaryen/test/unreachable-import_wasm-only.asm.js b/binaryen/test/unreachable-import_wasm-only.asm.js
deleted file mode 100644
--- a/binaryen/test/unreachable-import_wasm-only.asm.js
+++ /dev/null
@@ -1,107 +0,0 @@
-function asm(global, env, buffer) {
-  "use asm";
-
-  var HEAP8 = new global.Int8Array(buffer);
-  var HEAP16 = new global.Int16Array(buffer);
-  var HEAP32 = new global.Int32Array(buffer);
-  var HEAPU8 = new global.Uint8Array(buffer);
-  var HEAPU16 = new global.Uint16Array(buffer);
-  var HEAPU32 = new global.Uint32Array(buffer);
-  var HEAPF32 = new global.Float32Array(buffer);
-  var HEAPF64 = new global.Float64Array(buffer);
-
-  var DYNAMICTOP_PTR=env.DYNAMICTOP_PTR|0;
-  var tempDoublePtr=env.tempDoublePtr|0;
-  var ABORT=env.ABORT|0;
-  var STACKTOP=env.STACKTOP|0;
-  var STACK_MAX=env.STACK_MAX|0;
-  var ___async=env.___async|0;
-  var ___async_unwind=env.___async_unwind|0;
-  var ___async_retval=env.___async_retval|0;
-  var ___async_cur_frame=env.___async_cur_frame|0;
-
-  var __THREW__ = 0;
-  var threwValue = 0;
-  var setjmpId = 0;
-  var undef = 0;
-  var nan = global.NaN, inf = global.Infinity;
-  var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0;
-  var tempRet0 = 0;
-
-  var Math_floor=global.Math.floor;
-  var Math_abs=global.Math.abs;
-  var Math_sqrt=global.Math.sqrt;
-  var Math_pow=global.Math.pow;
-  var Math_cos=global.Math.cos;
-  var Math_sin=global.Math.sin;
-  var Math_tan=global.Math.tan;
-  var Math_acos=global.Math.acos;
-  var Math_asin=global.Math.asin;
-  var Math_atan=global.Math.atan;
-  var Math_atan2=global.Math.atan2;
-  var Math_exp=global.Math.exp;
-  var Math_log=global.Math.log;
-  var Math_ceil=global.Math.ceil;
-  var Math_imul=global.Math.imul;
-  var Math_min=global.Math.min;
-  var Math_max=global.Math.max;
-  var Math_clz32=global.Math.clz32;
-  var Math_fround=global.Math.fround;
-  var abort=env.abort;
-  var assert=env.assert;
-  var enlargeMemory=env.enlargeMemory;
-  var getTotalMemory=env.getTotalMemory;
-  var abortOnCannotGrowMemory=env.abortOnCannotGrowMemory;
-  var invoke_iiii=env.invoke_iiii;
-  var invoke_viiiii=env.invoke_viiiii;
-  var invoke_vi=env.invoke_vi;
-  var invoke_ii=env.invoke_ii;
-  var invoke_v=env.invoke_v;
-  var invoke_viiiiii=env.invoke_viiiiii;
-  var invoke_viiii=env.invoke_viiii;
-  var _pthread_cleanup_pop=env._pthread_cleanup_pop;
-  var _pthread_key_create=env._pthread_key_create;
-  var ___syscall6=env.___syscall6;
-  var ___gxx_personality_v0=env.___gxx_personality_v0;
-  var ___assert_fail=env.___assert_fail;
-  var ___cxa_allocate_exception=env.___cxa_allocate_exception;
-  var __ZSt18uncaught_exceptionv=env.__ZSt18uncaught_exceptionv;
-  var ___setErrNo=env.___setErrNo;
-  var ___cxa_begin_catch=env.___cxa_begin_catch;
-  var _emscripten_memcpy_big=env._emscripten_memcpy_big;
-  var ___resumeException=env.___resumeException;
-  var ___cxa_find_matching_catch=env.___cxa_find_matching_catch;
-  var _pthread_getspecific=env._pthread_getspecific;
-  var _pthread_once=env._pthread_once;
-  var ___syscall54=env.___syscall54;
-  var ___unlock=env.___unlock;
-  var _pthread_setspecific=env._pthread_setspecific;
-  var ___cxa_throw=env.___cxa_throw;
-  var ___lock=env.___lock;
-  var _abort=env._abort;
-  var _pthread_cleanup_push=env._pthread_cleanup_push;
-  var ___syscall140=env.___syscall140;
-  var ___cxa_pure_virtual=env.___cxa_pure_virtual;
-  var ___syscall146=env.___syscall146;
-  var tempFloat = Math_fround(0);
-  const f0 = Math_fround(0);
-
-function __ZN10WasmAssertC2Ev__async_cb($0) {
- $0 = $0|0;
- switch (0) {
- case 0:  {
-  store4(12,26);
-  return;
-  break;
- }
- default: {
-  $0 = (___cxa_allocate_exception(4)|0);
-  store4($0,1);
-  ___cxa_throw(($0|0),(1280|0),(0|0));
- }
- }
-}
-
-  return { __ZN10WasmAssertC2Ev__async_cb: __ZN10WasmAssertC2Ev__async_cb };
-}
-
diff --git a/binaryen/test/unreachable-instr-type.wast b/binaryen/test/unreachable-instr-type.wast
--- a/binaryen/test/unreachable-instr-type.wast
+++ b/binaryen/test/unreachable-instr-type.wast
@@ -19,7 +19,7 @@
       (i64.const 1)
     )
 
-    (i64.atomic.wait
+    (memory.atomic.wait64
       (unreachable)
       (i64.const 0)
       (i64.const 0)
diff --git a/binaryen/test/unreachable-instr-type.wast.from-wast b/binaryen/test/unreachable-instr-type.wast.from-wast
--- a/binaryen/test/unreachable-instr-type.wast.from-wast
+++ b/binaryen/test/unreachable-instr-type.wast.from-wast
@@ -18,7 +18,7 @@
    (i64.const 0)
    (i64.const 1)
   )
-  (i64.atomic.wait
+  (memory.atomic.wait64
    (unreachable)
    (i64.const 0)
    (i64.const 0)
diff --git a/binaryen/test/use-import-and-drop.asm.js b/binaryen/test/use-import-and-drop.asm.js
deleted file mode 100644
--- a/binaryen/test/use-import-and-drop.asm.js
+++ /dev/null
@@ -1,19 +0,0 @@
-Module["asm"] = (function(global, env, buffer) {
- "use asm";
- var setTempRet0=env.setTempRet0;
- var Math_imul = global.Math.imul;
- function test1() {
-  var $b$1 = 0, $x_sroa_0_0_extract_trunc = 0, $2 = 0, $1$1 = 0, $1$0 = 0;
-  // Here we use setTempRet0 as if it returns i32, and later as if no return value.
-  // We should *not* expand the return type to f64, as this is not an overloaded return value
-  return (setTempRet0((((Math_imul($b$1, $x_sroa_0_0_extract_trunc) | 0) + $2 | 0) + $1$1 | $1$1 & 0) | 0), 0 | $1$0 & -1) | 0;
- }
- function test2() {
-  setTempRet0(10);
- }
- return {
- };
-});
-
-
-
diff --git a/binaryen/test/wasm-only.asm.js b/binaryen/test/wasm-only.asm.js
deleted file mode 100644
--- a/binaryen/test/wasm-only.asm.js
+++ /dev/null
@@ -1,484 +0,0 @@
-//
-// Test wasm-only builds. In this case, fastcomp emits code that is
-// not asm.js, it will only ever run as wasm, and contains special intrinsics for
-// asm2wasm that map LLVM IR into i64s.
-//
-
-function asm(global, env, buffer) {
-  "use asm";
-
-  var HEAP8 = new global.Int8Array(buffer);
-  var HEAP16 = new global.Int16Array(buffer);
-  var HEAP32 = new global.Int32Array(buffer);
-  var HEAPU8 = new global.Uint8Array(buffer);
-  var HEAPU16 = new global.Uint16Array(buffer);
-  var HEAPU32 = new global.Uint32Array(buffer);
-  var HEAPF32 = new global.Float32Array(buffer);
-  var HEAPF64 = new global.Float64Array(buffer);
-
-  var STACKTOP = env.STACKTOP | 0;
-
-  var fround = global.Math.fround;
-  var Math_imul = global.Math.imul;
-
-  var illegalImport = env.illegalImport;
-  var illegalImportResult = env.illegalImportResult;
-
-  var _fabsf = env._fabsf;
-  var do_i64 = env.do_i64;
-  var abort = env.abort;
-
-  function loads() {
-    var i = 0, f = fround(0), d = +0;
-    i = load1(100);
-    i = load1(101, 0);
-    i = load2(102);
-    i = load2(103, 0);
-    i = load2(104, 1);
-    i = load2(105, 2);
-    i = load4(106);
-    i = load4(107, 0);
-    i = load4(108, 1);
-    i = load4(109, 2);
-    i = load4(110, 4);
-    f = loadf(111);
-    f = loadf(112, 0);
-    f = loadf(113, 1);
-    f = loadf(114, 2);
-    f = loadf(115, 4);
-    d = loadd(116);
-    d = loadd(117, 0);
-    d = loadd(118, 1);
-    d = loadd(119, 2);
-    d = loadd(120, 4);
-    d = loadd(121, 8);
-  }
-
-  function stores() {
-    var i = 0, f = fround(0), d = +0;
-    store1(100, i);
-    store1(101, i, 0);
-    store2(102, i);
-    store2(103, i, 0);
-    store2(104, i, 1);
-    store2(105, i, 2);
-    store4(106, i);
-    store4(107, i, 0);
-    store4(108, i, 1);
-    store4(109, i, 2);
-    store4(110, i, 4);
-    storef(111, f);
-    storef(112, f, 0);
-    storef(113, f, 1);
-    storef(114, f, 2);
-    storef(115, f, 4);
-    stored(116, d);
-    stored(117, d, 0);
-    stored(118, d, 1);
-    stored(119, d, 2);
-    stored(120, d, 4);
-    stored(121, d, 8);
-  }
-
-  function test() {
-    var i = 0, j = i64(), f = fround(0), f1 = fround(0), f2 = fround(0), d1 = +0, d2 = +0;
-    // bitcasts
-    i = i32_bc2i(f);
-    f = i32_bc2f(i);
-    i = i32_cttz(i);
-    i = i32_ctpop(i);
-    j = i64_ctpop(j);
-    f1 = f32_copysign(f1, f2);
-    d1 = f64_copysign(d1, d2);
-  }
-
-  function test64() {
-    var x = i64(), y = i64(), z = 0; // define i64 variables using special intrinsic
-    var int32 = 0, float32 = fround(0), float64 = +0;
-    x = i64_const(100, 0); // i64 constant
-    y = i64_const(17, 30);
-    x = i64_add(x, y); // binaries
-    x = i64_sub(x, y);
-    x = i64_mul(x, y);
-    x = i64_udiv(x, y);
-    x = i64_sdiv(x, y);
-    x = i64_urem(x, y);
-    x = i64_srem(x, y);
-    x = i64_and(x, y);
-    x = i64_or(x, y);
-    x = i64_xor(x, y);
-    x = i64_shl(x, y);
-    x = i64_ashr(x, y);
-    x = i64_lshr(x, y);
-    x = load8(120, 0); // load and store
-    x = load8(120);
-    x = load8(120, 2);
-    x = load8(120, 4);
-    x = load8(120, 8);
-    store8(120, x, 0);
-    store8(120, x);
-    store8(120, x, 2);
-    store8(120, x, 4);
-    store8(120, x, 8);
-    // comps
-    z = i64_eq(x, y);
-    z = i64_ne(x, y);
-    z = i64_ule(x, y);
-    z = i64_sle(x, y);
-    z = i64_uge(x, y);
-    z = i64_sge(x, y);
-    z = i64_ult(x, y);
-    z = i64_slt(x, y);
-    z = i64_ugt(x, y);
-    z = i64_sgt(x, y);
-    // convs
-    int32 = i64_trunc(x);
-    x = i64_sext(int32);
-    x = i64_zext(int32);
-    float32 = i64_s2f(x);
-    float64 = i64_s2d(x);
-    float32 = i64_u2f(x);
-    float64 = i64_u2d(x);
-    x = i64_f2s(float32);
-    x = i64_d2s(float64);
-    x = i64_f2u(float32);
-    x = i64_d2u(float64);
-    // bitcasts
-    x = i64_bc2i(float64);
-    float64 = i64_bc2d(x);
-    // intrinsics
-    x = i64_ctlz(y);
-    y = i64_cttz(x);
-  }
-  function imports() {
-    illegalImport(-3.13159, i64_const(11, 22), -33); // this call must be legalized
-    return i64(illegalImportResult());
-  }
-  function arg(x) { // illegal param, but not exported
-    x = i64(x);
-    store8(100, x, 0);
-    arg(i64(x)); // "coercion"/"cast"
-  }
-  function illegalParam(a, x, c) {
-    a = 0;
-    x = i64(x);
-    b = +0;
-    store4(50, a, 0);
-    store8(100, x, 0);
-    stored(200, b, 0);
-    illegalParam(0, i64(x), 12.34); // "coercion"/"cast"
-  }
-  function result() { // illegal result, but not exported
-    return i64_const(1, 2);
-  }
-  function illegalResult() { // illegal result, exported
-    return i64_const(1, 2);
-  }
-  function call1(x) {
-    x = i64(x);
-    var y = i64();
-    y = i64(call1(x));
-    return i64(y); // return i64 with a "cast"
-  }
-  function call2(x) {
-    x = i64(x);
-    i64(call2(i64(call2(x))));
-    return i64_const(591726473, 57073); // return an i64 const
-  }
-  function returnCastConst() {
-     return i64(0);
-  }
-  function ifValue64($4, $6) {
-   $4 = i64($4);
-   $6 = i64($6);
-   var $$0 = i64(), $9 = i64(), $10 = i64();
-   if ($6) {
-     $9 = i64(call2($4));
-     $$0 = $9;
-   } else {
-     $10 = i64(call2($4));
-     $$0 = $10;
-   }
-   return i64($$0);
-  }
-  function ifValue32($4, $6) {
-   $4 = $4 | 0;
-   $6 = $6 | 0;
-   var $$0 = 0, $9 = 0, $10 = 0;
-   if ($6) {
-     $9 = ifValue32($4 | 0, $6 | 0) | 0;
-     $$0 = $9;
-   } else {
-     $10 = ifValue32($4 | 0, $6 | 0) | 0;
-     $$0 = $10;
-   }
-   return $$0 | 0;
-  }
-  function switch64($a444) {
-    $a444 = i64($a444);
-    var $waka = 0;
-    switch (i64($a444)) {
-     case i64_const(7,10):  {
-      $waka = 11000;
-      break;
-     }
-     case i64_const(5,10):  {
-      $waka = 10;
-      break;
-     }
-     default: {
-      $waka = 1;
-     }
-    }
-    return $waka | 0;
-  }
-  function unreachable_leftovers($0,$1,$2) {
-   $0 = $0|0;
-   $1 = $1|0;
-   $2 = $2|0;
-   var label = 0;
-   L1: do {
-    if ($1) {
-     label = 10;
-    } else {
-     if ($2) {
-      break L1;
-      return;
-     }
-     store4($0,-2);
-     return;
-    }
-   } while(0);
-   if ((label|0) == 10) {
-    store4($0,-1);
-   }
-   return;
-  }
-  function switch64TOOMUCH($a444) {
-    $a444 = i64($a444);
-    var $waka = 0;
-    switch (i64($a444)) {
-     case i64_const(0,1073741824): // spread is huge here, we should not make a jump table!
-     case i64_const(0,2147483648):  {
-      return 40;
-     }
-     default: {
-      $waka = 1;
-     }
-    }
-    switch (100) {
-     case 107374182: // similar, but 32-bit
-     case 214748364:  {
-      return 41;
-     }
-     default: {
-      $waka = 1001;
-     }
-    }
-    // no defaults
-    switch (i64($a444)) {
-     case i64_const(0,1073741824): // spread is huge here, we should not make a jump table!
-     case i64_const(0,2147483648):  {
-      return 42;
-     }
-    }
-    switch (100) {
-     case 107374182: // similar, but 32-bit
-     case 214748364:  {
-      return 43;
-     }
-    }
-    return 44;
-  }
-  function _memchr($src,$c,$n) {
-   $src = $src|0;
-   $c = $c|0;
-   $n = $n|0;
-   var $0 = 0, $1 = 0, $2 = 0, $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0, $and = 0, $and15 = 0, $and16 = 0, $and39 = 0, $cmp = 0, $cmp11 = 0, $cmp1132 = 0, $cmp28 = 0, $cmp8 = 0, $cond = 0, $conv1 = 0, $dec = 0;
-   var $dec34 = 0, $incdec$ptr = 0, $incdec$ptr21 = 0, $incdec$ptr33 = 0, $lnot = 0, $mul = 0, $n$addr$0$lcssa = 0, $n$addr$0$lcssa52 = 0, $n$addr$043 = 0, $n$addr$1$lcssa = 0, $n$addr$133 = 0, $n$addr$227 = 0, $n$addr$3 = 0, $neg = 0, $or$cond = 0, $or$cond42 = 0, $s$0$lcssa = 0, $s$0$lcssa53 = 0, $s$044 = 0, $s$128 = 0;
-   var $s$2 = 0, $sub = 0, $sub22 = 0, $tobool = 0, $tobool2 = 0, $tobool2$lcssa = 0, $tobool241 = 0, $tobool25 = 0, $tobool2526 = 0, $tobool36 = 0, $tobool40 = 0, $w$0$lcssa = 0, $w$034 = 0, $xor = 0, label = 0, sp = 0;
-   sp = STACKTOP;
-   $conv1 = $c & 255;
-   $0 = $src;
-   $and39 = $0 & 3;
-   $tobool40 = ($and39|0)!=(0);
-   $tobool241 = ($n|0)!=(0);
-   $or$cond42 = $tobool241 & $tobool40;
-   L1: do {
-    if ($or$cond42) {
-     $1 = $c&255;
-     $n$addr$043 = $n;$s$044 = $src;
-     while(1) {
-      $2 = load1($s$044);
-      $cmp = ($2<<24>>24)==($1<<24>>24);
-      if ($cmp) {
-       $n$addr$0$lcssa52 = $n$addr$043;$s$0$lcssa53 = $s$044;
-       label = 6;
-       break L1;
-      }
-      $incdec$ptr = ((($s$044)) + 1|0);
-      $dec = (($n$addr$043) + -1)|0;
-      $3 = $incdec$ptr;
-      $and = $3 & 3;
-      $tobool = ($and|0)!=(0);
-      $tobool2 = ($dec|0)!=(0);
-      $or$cond = $tobool2 & $tobool;
-      if ($or$cond) {
-       $n$addr$043 = $dec;$s$044 = $incdec$ptr;
-      } else {
-       $n$addr$0$lcssa = $dec;$s$0$lcssa = $incdec$ptr;$tobool2$lcssa = $tobool2;
-       label = 5;
-       break;
-      }
-     }
-    } else {
-     $n$addr$0$lcssa = $n;$s$0$lcssa = $src;$tobool2$lcssa = $tobool241;
-     label = 5;
-    }
-   } while(0);
-   if ((label|0) == 5) {
-    if ($tobool2$lcssa) {
-     $n$addr$0$lcssa52 = $n$addr$0$lcssa;$s$0$lcssa53 = $s$0$lcssa;
-     label = 6;
-    } else {
-     $n$addr$3 = 0;$s$2 = $s$0$lcssa;
-    }
-   }
-   L8: do {
-    if ((label|0) == 6) {
-     $4 = load1($s$0$lcssa53);
-     $5 = $c&255;
-     $cmp8 = ($4<<24>>24)==($5<<24>>24);
-     if ($cmp8) {
-      $n$addr$3 = $n$addr$0$lcssa52;$s$2 = $s$0$lcssa53;
-     } else {
-      $mul = Math_imul($conv1, 16843009)|0;
-      $cmp1132 = ($n$addr$0$lcssa52>>>0)>(3);
-      L11: do {
-       if ($cmp1132) {
-        $n$addr$133 = $n$addr$0$lcssa52;$w$034 = $s$0$lcssa53;
-        while(1) {
-         $6 = load4($w$034);
-         $xor = $6 ^ $mul;
-         $sub = (($xor) + -16843009)|0;
-         $neg = $xor & -2139062144;
-         $and15 = $neg ^ -2139062144;
-         $and16 = $and15 & $sub;
-         $lnot = ($and16|0)==(0);
-         if (!($lnot)) {
-          break;
-         }
-         $incdec$ptr21 = ((($w$034)) + 4|0);
-         $sub22 = (($n$addr$133) + -4)|0;
-         $cmp11 = ($sub22>>>0)>(3);
-         if ($cmp11) {
-          $n$addr$133 = $sub22;$w$034 = $incdec$ptr21;
-         } else {
-          $n$addr$1$lcssa = $sub22;$w$0$lcssa = $incdec$ptr21;
-          label = 11;
-          break L11;
-         }
-        }
-        $n$addr$227 = $n$addr$133;$s$128 = $w$034;
-       } else {
-        $n$addr$1$lcssa = $n$addr$0$lcssa52;$w$0$lcssa = $s$0$lcssa53;
-        label = 11;
-       }
-      } while(0);
-      if ((label|0) == 11) {
-       $tobool2526 = ($n$addr$1$lcssa|0)==(0);
-       if ($tobool2526) {
-        $n$addr$3 = 0;$s$2 = $w$0$lcssa;
-        break;
-       } else {
-        $n$addr$227 = $n$addr$1$lcssa;$s$128 = $w$0$lcssa;
-       }
-      }
-      while(1) {
-       $7 = load1($s$128);
-       $cmp28 = ($7<<24>>24)==($5<<24>>24);
-       if ($cmp28) {
-        $n$addr$3 = $n$addr$227;$s$2 = $s$128;
-        break L8;
-       }
-       $incdec$ptr33 = ((($s$128)) + 1|0);
-       $dec34 = (($n$addr$227) + -1)|0;
-       $tobool25 = ($dec34|0)==(0);
-       if ($tobool25) {
-        $n$addr$3 = 0;$s$2 = $incdec$ptr33;
-        break;
-       } else {
-        $n$addr$227 = $dec34;$s$128 = $incdec$ptr33;
-       }
-      }
-     }
-    }
-   } while(0);
-   $tobool36 = ($n$addr$3|0)!=(0);
-   $cond = $tobool36 ? $s$2 : 0;
-   return ($cond|0);
-  }
-
-  function switch64_big_condition1($x) {
-    $x = i64($x);
-    switch (i64($x)) {
-      case i64_const(0,2146435072):  {
-        abort();
-        break;
-      }
-      default: {
-        return;
-      }
-    }
-  }
-  function switch64_big_condition2($x) {
-    $x = i64($x);
-    switch (i64($x)) {
-      case i64_const(0,2146435072):  {
-        abort();
-        break;
-      }
-    }
-  }
-
-  function keepAlive() {
-    loads();
-    loads();
-    stores();
-    stores();
-    test();
-    test();
-    i64(imports());
-    i64(imports());
-    arg(i64(0));
-    arg(i64(0));
-    i64(call1(i64(0)));
-    i64(call1(i64(0)));
-    i64(call2(i64(0)));
-    i64(call2(i64(0)));
-    i64(returnCastConst());
-    i64(returnCastConst());
-    i64(ifValue64(i64(0), i64(0)));
-    i64(ifValue64(i64(0), i64(0)));
-    ifValue32(0, 0) | 0;
-    ifValue32(0, 0) | 0;
-    switch64(i64(0)) | 0;
-    switch64(i64(0)) | 0;
-    unreachable_leftovers(0, 0, 0);
-    unreachable_leftovers(0, 0, 0);
-    _memchr(0, 0, 0) | 0;
-    switch64TOOMUCH(i64(0)) | 0;
-    switch64_big_condition1(i64(0));
-    switch64_big_condition2(i64(0));
-  }
-
-  function __emscripten_dceable_type_decls() { // dce-able, but this defines the type of fabsf which has no other use
-    fround(_fabsf(fround(0.0)));
-    i64(do_i64());
-  }
-
-  var FUNCTION_TABLE_X = [illegalImport, _fabsf, do_i64]; // must stay ok in the table, not legalized, as it will be called internally by the true type
-
-  return { test64: test64, illegalParam : illegalParam, illegalResult: illegalResult, keepAlive: keepAlive };
-}
-
diff --git a/binaryen/test/wasm2js.asserts.js b/binaryen/test/wasm2js.asserts.js
--- a/binaryen/test/wasm2js.asserts.js
+++ b/binaryen/test/wasm2js.asserts.js
@@ -30,19 +30,20 @@
        return (actual_lo | 0) == (expected_lo | 0) && (actual_hi | 0) == (expected_hi | 0);
     }
   
-function asmFunc0(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc0(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   
  }
@@ -66,20 +67,7 @@
  };
 }
 
-var retasmFunc0 = asmFunc0({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc0 = asmFunc0(  { abort: function() { throw new Error('abort'); }
   });
 function check1() {
  retasmFunc0.empty();
diff --git a/binaryen/test/wasm2js.traps.js b/binaryen/test/wasm2js.traps.js
--- a/binaryen/test/wasm2js.traps.js
+++ b/binaryen/test/wasm2js.traps.js
@@ -30,19 +30,20 @@
        return (actual_lo | 0) == (expected_lo | 0) && (actual_hi | 0) == (expected_hi | 0);
     }
   
-function asmFunc0(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc0(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   
  }
@@ -66,20 +67,7 @@
  };
 }
 
-var retasmFunc0 = asmFunc0({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc0 = asmFunc0(  { abort: function() { throw new Error('abort'); }
   });
 function check1() {
  retasmFunc0.empty();
diff --git a/binaryen/test/wasm2js/add_div.2asm.js b/binaryen/test/wasm2js/add_div.2asm.js
--- a/binaryen/test/wasm2js/add_div.2asm.js
+++ b/binaryen/test/wasm2js/add_div.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function foo($0) {
   $0 = $0 | 0;
   return (($0 >>> 0) / (100 >>> 0) | 0) + (($0 | 0) / (-100 | 0) | 0) | 0 | 0;
@@ -22,19 +23,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/add_div.2asm.js.opt b/binaryen/test/wasm2js/add_div.2asm.js.opt
--- a/binaryen/test/wasm2js/add_div.2asm.js.opt
+++ b/binaryen/test/wasm2js/add_div.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function foo($0) {
   $0 = $0 | 0;
   return (($0 | 0) / -100 | 0) + (($0 >>> 0) / 100 | 0) | 0;
@@ -22,19 +23,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/atomic_fence.2asm.js b/binaryen/test/wasm2js/atomic_fence.2asm.js
--- a/binaryen/test/wasm2js/atomic_fence.2asm.js
+++ b/binaryen/test/wasm2js/atomic_fence.2asm.js
@@ -1,25 +1,27 @@
 
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(1507328);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   
  }
@@ -34,17 +36,16 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
   }
   return oldPages;
@@ -55,23 +56,6 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(1507328);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var atomic_fence = retasmFunc.atomic_fence;
diff --git a/binaryen/test/wasm2js/atomic_fence.2asm.js.opt b/binaryen/test/wasm2js/atomic_fence.2asm.js.opt
--- a/binaryen/test/wasm2js/atomic_fence.2asm.js.opt
+++ b/binaryen/test/wasm2js/atomic_fence.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   
  }
@@ -21,19 +22,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var atomic_fence = retasmFunc.atomic_fence;
diff --git a/binaryen/test/wasm2js/atomics_32.2asm.js b/binaryen/test/wasm2js/atomics_32.2asm.js
--- a/binaryen/test/wasm2js/atomics_32.2asm.js
+++ b/binaryen/test/wasm2js/atomics_32.2asm.js
@@ -1,4 +1,28 @@
 
+  var bufferView;
+  var memorySegments = {};
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "aGVsbG8s");
+memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29ybGQh");
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -65,29 +89,29 @@
     bufferView.set(memorySegments[segment].subarray(offset, offset + size), dest);
   }
       
-  var memorySegments = {};
-    
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(16777216);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$1 = 0;
   Atomics.compareExchange(HEAP8, 1024, 1, 2) | 0;
@@ -119,6 +143,7 @@
   i64toi32_i32$0 = wasm2js_get_stashed_bits() | 0;
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -128,44 +153,6 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(16777216);
-var bufferView = new Uint8Array(memasmFunc);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "aGVsbG8s");
-memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29ybGQh");
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var test = retasmFunc.test;
diff --git a/binaryen/test/wasm2js/atomics_32.2asm.js.opt b/binaryen/test/wasm2js/atomics_32.2asm.js.opt
--- a/binaryen/test/wasm2js/atomics_32.2asm.js.opt
+++ b/binaryen/test/wasm2js/atomics_32.2asm.js.opt
@@ -1,4 +1,28 @@
 
+  var bufferView;
+  var memorySegments = {};
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "aGVsbG8s");
+memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29ybGQh");
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -65,29 +89,29 @@
     bufferView.set(memorySegments[segment].subarray(offset, offset + size), dest);
   }
       
-  var memorySegments = {};
-    
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(16777216);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   Atomics.compareExchange(HEAP8, 1024, 1, 2) | 0;
   Atomics.compareExchange(HEAP16, 512, 1, 2) | 0;
@@ -115,6 +139,7 @@
   wasm2js_get_stashed_bits() | 0;
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -124,44 +149,6 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(16777216);
-var bufferView = new Uint8Array(memasmFunc);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "aGVsbG8s");
-memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29ybGQh");
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var test = retasmFunc.test;
diff --git a/binaryen/test/wasm2js/atomics_32.wast b/binaryen/test/wasm2js/atomics_32.wast
--- a/binaryen/test/wasm2js/atomics_32.wast
+++ b/binaryen/test/wasm2js/atomics_32.wast
@@ -12,11 +12,11 @@
     (local.set $x (i32.atomic.load16_u (i32.const 1028)))
     (local.set $x (i32.atomic.load (i32.const 1028)))
     (i32.atomic.store (i32.const 100) (i32.const 200))
-    (local.set $x (i32.atomic.wait (i32.const 4) (i32.const 8) (i64.const -1)))
+    (local.set $x (memory.atomic.wait32 (i32.const 4) (i32.const 8) (i64.const -1)))
     (memory.init 0 (i32.const 512) (i32.const 0) (i32.const 4))
     (memory.init 1 (i32.const 1024) (i32.const 4) (i32.const 2))
-    (local.set $x (atomic.notify (i32.const 4) (i32.const 2)))
-    (local.set $x (atomic.notify offset=20 (i32.const 4) (i32.const 2)))
+    (local.set $x (memory.atomic.notify (i32.const 4) (i32.const 2)))
+    (local.set $x (memory.atomic.notify offset=20 (i32.const 4) (i32.const 2)))
     (local.set $x (i32.atomic.rmw.add (i32.const 8) (i32.const 12)))
     (local.set $x (i32.atomic.rmw.sub (i32.const 8) (i32.const 12)))
     (local.set $x (i32.atomic.rmw.and (i32.const 8) (i32.const 12)))
diff --git a/binaryen/test/wasm2js/base64.2asm.js b/binaryen/test/wasm2js/base64.2asm.js
--- a/binaryen/test/wasm2js/base64.2asm.js
+++ b/binaryen/test/wasm2js/base64.2asm.js
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/base64.2asm.js.opt b/binaryen/test/wasm2js/base64.2asm.js.opt
--- a/binaryen/test/wasm2js/base64.2asm.js.opt
+++ b/binaryen/test/wasm2js/base64.2asm.js.opt
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/br.2asm.js b/binaryen/test/wasm2js/br.2asm.js
--- a/binaryen/test/wasm2js/br.2asm.js
+++ b/binaryen/test/wasm2js/br.2asm.js
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function dummy() {
@@ -106,8 +107,10 @@
  function $13() {
   var $0 = 0, $1_1 = 0, $3_1 = 0;
   block : {
-   $0 = 3;
-   break block;
+   loop_in : while (1) {
+    $0 = 3;
+    break block;
+   };
   }
   return $0 | 0;
  }
@@ -115,9 +118,11 @@
  function $14() {
   var $0 = 0, $1_1 = 0, $3_1 = 0;
   block : {
-   dummy();
-   $0 = 4;
-   break block;
+   loop_in : while (1) {
+    dummy();
+    $0 = 4;
+    break block;
+   };
   }
   return $0 | 0;
  }
@@ -125,9 +130,11 @@
  function $15() {
   var $0 = 0;
   block : {
-   dummy();
-   $0 = 5;
-   break block;
+   loop_in : while (1) {
+    dummy();
+    $0 = 5;
+    break block;
+   };
   }
   return $0 | 0;
  }
@@ -709,20 +716,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var type_i32 = retasmFunc.type_i32;
diff --git a/binaryen/test/wasm2js/br_table.2asm.js b/binaryen/test/wasm2js/br_table.2asm.js
--- a/binaryen/test/wasm2js/br_table.2asm.js
+++ b/binaryen/test/wasm2js/br_table.2asm.js
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function dummy() {
@@ -12560,10 +12561,12 @@
  function $20() {
   var $1_1 = 0, $2_1 = 0, $4_1 = 0;
   fake_return_waka123 : {
-   $1_1 = 3;
-   switch (0 | 0) {
-   default:
-    break fake_return_waka123;
+   loop_in : while (1) {
+    $1_1 = 3;
+    switch (0 | 0) {
+    default:
+     break fake_return_waka123;
+    };
    };
   }
   return $1_1 | 0;
@@ -12572,11 +12575,13 @@
  function $21() {
   var $1_1 = 0, $2_1 = 0, $4_1 = 0;
   fake_return_waka123 : {
-   dummy();
-   $1_1 = 4;
-   switch (-1 | 0) {
-   default:
-    break fake_return_waka123;
+   loop_in : while (1) {
+    dummy();
+    $1_1 = 4;
+    switch (-1 | 0) {
+    default:
+     break fake_return_waka123;
+    };
    };
   }
   return $1_1 | 0;
@@ -12585,11 +12590,13 @@
  function $22() {
   var $1_1 = 0;
   fake_return_waka123 : {
-   dummy();
-   $1_1 = 5;
-   switch (1 | 0) {
-   default:
-    break fake_return_waka123;
+   loop_in : while (1) {
+    dummy();
+    $1_1 = 5;
+    switch (1 | 0) {
+    default:
+     break fake_return_waka123;
+    };
    };
   }
   return $1_1 | 0;
@@ -13414,20 +13421,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var type_i32 = retasmFunc.type_i32;
diff --git a/binaryen/test/wasm2js/br_table_hoisting.2asm.js b/binaryen/test/wasm2js/br_table_hoisting.2asm.js
--- a/binaryen/test/wasm2js/br_table_hoisting.2asm.js
+++ b/binaryen/test/wasm2js/br_table_hoisting.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function zed($0) {
   $0 = $0 | 0;
   zed($0 | 0);
@@ -176,20 +177,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var foo1 = retasmFunc.foo1;
 export var foo2 = retasmFunc.foo2;
diff --git a/binaryen/test/wasm2js/br_table_hoisting.2asm.js.opt b/binaryen/test/wasm2js/br_table_hoisting.2asm.js.opt
--- a/binaryen/test/wasm2js/br_table_hoisting.2asm.js.opt
+++ b/binaryen/test/wasm2js/br_table_hoisting.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function zed($0) {
   zed($0);
  }
@@ -166,20 +167,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var foo1 = retasmFunc.foo1;
 export var foo2 = retasmFunc.foo2;
diff --git a/binaryen/test/wasm2js/br_table_temp.2asm.js b/binaryen/test/wasm2js/br_table_temp.2asm.js
--- a/binaryen/test/wasm2js/br_table_temp.2asm.js
+++ b/binaryen/test/wasm2js/br_table_temp.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function dummy() {
   
  }
@@ -12556,10 +12557,12 @@
  function $20() {
   var $1_1 = 0, $2_1 = 0, $4_1 = 0;
   fake_return_waka123 : {
-   $1_1 = 3;
-   switch (0 | 0) {
-   default:
-    break fake_return_waka123;
+   loop_in : while (1) {
+    $1_1 = 3;
+    switch (0 | 0) {
+    default:
+     break fake_return_waka123;
+    };
    };
   }
   return $1_1 | 0;
@@ -12568,11 +12571,13 @@
  function $21() {
   var $1_1 = 0, $2_1 = 0, $4_1 = 0;
   fake_return_waka123 : {
-   dummy();
-   $1_1 = 4;
-   switch (-1 | 0) {
-   default:
-    break fake_return_waka123;
+   loop_in : while (1) {
+    dummy();
+    $1_1 = 4;
+    switch (-1 | 0) {
+    default:
+     break fake_return_waka123;
+    };
    };
   }
   return $1_1 | 0;
@@ -12581,11 +12586,13 @@
  function $22() {
   var $1_1 = 0;
   fake_return_waka123 : {
-   dummy();
-   $1_1 = 5;
-   switch (1 | 0) {
-   default:
-    break fake_return_waka123;
+   loop_in : while (1) {
+    dummy();
+    $1_1 = 5;
+    switch (1 | 0) {
+    default:
+     break fake_return_waka123;
+    };
    };
   }
   return $1_1 | 0;
@@ -13257,20 +13264,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var type_i32 = retasmFunc.type_i32;
 export var type_i64 = retasmFunc.type_i64;
diff --git a/binaryen/test/wasm2js/br_table_temp.2asm.js.opt b/binaryen/test/wasm2js/br_table_temp.2asm.js.opt
--- a/binaryen/test/wasm2js/br_table_temp.2asm.js.opt
+++ b/binaryen/test/wasm2js/br_table_temp.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function dummy() {
   
  }
@@ -12611,10 +12612,10 @@
  
  function $63($0) {
   $0 = $0 | 0;
-  if ($0 - 1 | 0) {
-   $0 = 9
-  } else {
+  if (($0 | 0) == 1) {
    $0 = 8
+  } else {
+   $0 = 9
   }
   return $0 | 0;
  }
@@ -12687,20 +12688,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var type_i32 = retasmFunc.type_i32;
 export var type_i64 = retasmFunc.type_i64;
diff --git a/binaryen/test/wasm2js/br_table_to_loop.2asm.js b/binaryen/test/wasm2js/br_table_to_loop.2asm.js
--- a/binaryen/test/wasm2js/br_table_to_loop.2asm.js
+++ b/binaryen/test/wasm2js/br_table_to_loop.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   block : {
    loop : while (1) switch (1 | 0) {
@@ -40,20 +41,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var exp1 = retasmFunc.exp1;
 export var exp2 = retasmFunc.exp2;
diff --git a/binaryen/test/wasm2js/br_table_to_loop.2asm.js.opt b/binaryen/test/wasm2js/br_table_to_loop.2asm.js.opt
--- a/binaryen/test/wasm2js/br_table_to_loop.2asm.js.opt
+++ b/binaryen/test/wasm2js/br_table_to_loop.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   while (1) continue;
  }
@@ -26,20 +27,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var exp1 = retasmFunc.exp1;
 export var exp2 = retasmFunc.exp2;
diff --git a/binaryen/test/wasm2js/break-drop.2asm.js b/binaryen/test/wasm2js/break-drop.2asm.js
--- a/binaryen/test/wasm2js/break-drop.2asm.js
+++ b/binaryen/test/wasm2js/break-drop.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   
  }
@@ -31,20 +32,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var br = retasmFunc.br;
 export var br_if = retasmFunc.br_if;
diff --git a/binaryen/test/wasm2js/bulk-memory.2asm.js b/binaryen/test/wasm2js/bulk-memory.2asm.js
--- a/binaryen/test/wasm2js/bulk-memory.2asm.js
+++ b/binaryen/test/wasm2js/bulk-memory.2asm.js
@@ -1,38 +1,27 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 
+  var bufferView;
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -46,27 +35,29 @@
     bufferView.fill(value, dest, dest + size);
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0($0_1, $1_1, $2) {
   $0_1 = $0_1 | 0;
   $1_1 = $1_1 | 0;
@@ -79,6 +70,7 @@
   return HEAPU8[$0_1 >> 0] | 0 | 0;
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -89,18 +81,18 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
+   bufferView = HEAPU8;
   }
   return oldPages;
  }
@@ -111,28 +103,35 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var fill = retasmFunc.fill;
 export var load8_u = retasmFunc.load8_u;
 
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, 0, "qrvM3Q==");
+}
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -144,27 +143,29 @@
     bufferView.copyWithin(dest, source, source + size);
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0($0_1, $1_1, $2) {
   $0_1 = $0_1 | 0;
   $1_1 = $1_1 | 0;
@@ -177,6 +178,8 @@
   return HEAPU8[$0_1 >> 0] | 0 | 0;
  }
  
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -187,9 +190,15 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
+export var copy = retasmFunc.copy;
+export var load8_u = retasmFunc.load8_u;
+
+  var bufferView;
+  var memorySegments = {};
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
     base64ReverseLookup[48+i] = 52+i; // '0-9'
     base64ReverseLookup[65+i] = i; // 'A-Z'
     base64ReverseLookup[97+i] = 26+i; // 'a-z'
@@ -206,29 +215,9 @@
       if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
       if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
     }
-    return uint8Array; 
+    return uint8Array;
   }
-  base64DecodeToExistingUint8Array(bufferView, 0, "qrvM3Q==");
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
-export var copy = retasmFunc.copy;
-export var load8_u = retasmFunc.load8_u;
-
+memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(4), 0, "qrvM3Q==");
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -240,29 +229,29 @@
     bufferView.set(memorySegments[segment].subarray(offset, offset + size), dest);
   }
       
-  var memorySegments = {};
-    
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0($0_1, $1_1, $2) {
   $0_1 = $0_1 | 0;
   $1_1 = $1_1 | 0;
@@ -275,6 +264,7 @@
   return HEAPU8[$0_1 >> 0] | 0 | 0;
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -285,18 +275,18 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
+   bufferView = HEAPU8;
   }
   return oldPages;
  }
@@ -307,9 +297,15 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
+export var init = retasmFunc.init;
+export var load8_u = retasmFunc.load8_u;
+
+  var bufferView;
+  var memorySegments = {};
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
     base64ReverseLookup[48+i] = 52+i; // '0-9'
     base64ReverseLookup[65+i] = i; // 'A-Z'
     base64ReverseLookup[97+i] = 26+i; // 'a-z'
@@ -326,29 +322,12 @@
       if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
       if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
     }
-    return uint8Array; 
+    return uint8Array;
   }
-  memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(4), 0, "qrvM3Q==");
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
-export var init = retasmFunc.init;
-export var load8_u = retasmFunc.load8_u;
-
+memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(0), 0, "");
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, 0, "");
+}
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -365,29 +344,29 @@
     bufferView.set(memorySegments[segment].subarray(offset, offset + size), dest);
   }
       
-  var memorySegments = {};
-    
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   wasm2js_data_drop(0);
  }
@@ -404,6 +383,8 @@
   wasm2js_memory_init(1, 0, 0, 0);
  }
  
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -414,18 +395,18 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
+   bufferView = HEAPU8;
   }
   return oldPages;
  }
@@ -438,46 +419,8 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(0), 0, "");
-base64DecodeToExistingUint8Array(bufferView, 0, "");
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var drop_passive = retasmFunc.drop_passive;
 export var init_passive = retasmFunc.init_passive;
 export var drop_active = retasmFunc.drop_active;
diff --git a/binaryen/test/wasm2js/bulk-memory.2asm.js.opt b/binaryen/test/wasm2js/bulk-memory.2asm.js.opt
--- a/binaryen/test/wasm2js/bulk-memory.2asm.js.opt
+++ b/binaryen/test/wasm2js/bulk-memory.2asm.js.opt
@@ -1,38 +1,27 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 
+  var bufferView;
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -46,27 +35,29 @@
     bufferView.fill(value, dest, dest + size);
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0($0_1, $1_1, $2) {
   $0_1 = $0_1 | 0;
   $1_1 = $1_1 | 0;
@@ -79,6 +70,7 @@
   return HEAPU8[$0_1 | 0];
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -89,18 +81,18 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
+   bufferView = HEAPU8;
   }
   return oldPages;
  }
@@ -111,28 +103,35 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var fill = retasmFunc.fill;
 export var load8_u = retasmFunc.load8_u;
 
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, 0, "qrvM3Q==");
+}
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -144,27 +143,29 @@
     bufferView.copyWithin(dest, source, source + size);
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0($0_1, $1_1, $2) {
   $0_1 = $0_1 | 0;
   $1_1 = $1_1 | 0;
@@ -177,6 +178,8 @@
   return HEAPU8[$0_1 | 0];
  }
  
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -187,9 +190,15 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
+export var copy = retasmFunc.copy;
+export var load8_u = retasmFunc.load8_u;
+
+  var bufferView;
+  var memorySegments = {};
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
     base64ReverseLookup[48+i] = 52+i; // '0-9'
     base64ReverseLookup[65+i] = i; // 'A-Z'
     base64ReverseLookup[97+i] = 26+i; // 'a-z'
@@ -206,29 +215,9 @@
       if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
       if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
     }
-    return uint8Array; 
+    return uint8Array;
   }
-  base64DecodeToExistingUint8Array(bufferView, 0, "qrvM3Q==");
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
-export var copy = retasmFunc.copy;
-export var load8_u = retasmFunc.load8_u;
-
+memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(4), 0, "qrvM3Q==");
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -240,29 +229,29 @@
     bufferView.set(memorySegments[segment].subarray(offset, offset + size), dest);
   }
       
-  var memorySegments = {};
-    
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0($0_1, $1_1, $2) {
   $0_1 = $0_1 | 0;
   $1_1 = $1_1 | 0;
@@ -275,6 +264,7 @@
   return HEAPU8[$0_1 | 0];
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -285,18 +275,18 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
+   bufferView = HEAPU8;
   }
   return oldPages;
  }
@@ -307,75 +297,40 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(4), 0, "qrvM3Q==");
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var init = retasmFunc.init;
 export var load8_u = retasmFunc.load8_u;
 
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   
  }
  
  function $1() {
-  if (0 > __wasm_memory_size() << 16 >>> 0) {
+  if (__wasm_memory_size() << 16 >>> 0 < 0) {
    abort()
   }
  }
@@ -390,17 +345,16 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
   }
   return oldPages;
@@ -414,25 +368,8 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var drop_passive = retasmFunc.drop_passive;
 export var init_passive = retasmFunc.init_passive;
 export var drop_active = retasmFunc.drop_active;
diff --git a/binaryen/test/wasm2js/comments.2asm.js b/binaryen/test/wasm2js/comments.2asm.js
--- a/binaryen/test/wasm2js/comments.2asm.js
+++ b/binaryen/test/wasm2js/comments.2asm.js
@@ -1,68 +1,44 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/conversions-modified.2asm.js b/binaryen/test/wasm2js/conversions-modified.2asm.js
--- a/binaryen/test/wasm2js/conversions-modified.2asm.js
+++ b/binaryen/test/wasm2js/conversions-modified.2asm.js
@@ -30,19 +30,20 @@
     f32ScratchView[2] = value;
   }
       
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0(x) {
@@ -618,20 +619,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i64_extend_s_i32 = retasmFunc.i64_extend_s_i32;
diff --git a/binaryen/test/wasm2js/conversions-modified.2asm.js.opt b/binaryen/test/wasm2js/conversions-modified.2asm.js.opt
--- a/binaryen/test/wasm2js/conversions-modified.2asm.js.opt
+++ b/binaryen/test/wasm2js/conversions-modified.2asm.js.opt
@@ -30,19 +30,20 @@
     f32ScratchView[2] = value;
   }
       
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $3($0) {
@@ -67,13 +68,13 @@
  
  function $7($0) {
   $0 = Math_fround($0);
-  i64toi32_i32$HIGH_BITS = Math_fround(Math_abs($0)) >= Math_fround(1.0) ? ($0 > Math_fround(0.0) ? ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround($0 / Math_fround(4294967296.0)))), Math_fround(4294967296.0))) >>> 0 : ~~Math_fround(Math_ceil(Math_fround(Math_fround($0 - Math_fround(~~$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0) : 0;
+  i64toi32_i32$HIGH_BITS = Math_fround(Math_abs($0)) >= Math_fround(1.0) ? ($0 > Math_fround(0.0) ? ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround($0 * Math_fround(2.3283064365386963e-10)))), Math_fround(4294967296.0))) >>> 0 : ~~Math_fround(Math_ceil(Math_fround(Math_fround($0 - Math_fround(~~$0 >>> 0 >>> 0)) * Math_fround(2.3283064365386963e-10)))) >>> 0) : 0;
   return ~~$0 >>> 0 | 0;
  }
  
  function $9($0) {
   $0 = +$0;
-  i64toi32_i32$HIGH_BITS = Math_abs($0) >= 1.0 ? ($0 > 0.0 ? ~~Math_min(Math_floor($0 / 4294967296.0), 4294967295.0) >>> 0 : ~~Math_ceil(($0 - +(~~$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0) : 0;
+  i64toi32_i32$HIGH_BITS = Math_abs($0) >= 1.0 ? ($0 > 0.0 ? ~~Math_min(Math_floor($0 * 2.3283064365386963e-10), 4294967295.0) >>> 0 : ~~Math_ceil(($0 - +(~~$0 >>> 0 >>> 0)) * 2.3283064365386963e-10) >>> 0) : 0;
   return ~~$0 >>> 0 | 0;
  }
  
@@ -209,20 +210,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i64_extend_s_i32 = retasmFunc.i64_extend_s_i32;
diff --git a/binaryen/test/wasm2js/deterministic.2asm.js b/binaryen/test/wasm2js/deterministic.2asm.js
--- a/binaryen/test/wasm2js/deterministic.2asm.js
+++ b/binaryen/test/wasm2js/deterministic.2asm.js
@@ -1,27 +1,28 @@
 
-function asmFunc(global, env) {
+function asmFunc(env) {
  var memory = env.memory;
  var buffer = memory.buffer;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var global$0 = -44;
  function $0() {
   if ((global$0 >>> 0) / ((HEAP32[0 >> 2] | 0) >>> 0) | 0) {
@@ -40,21 +41,7 @@
 }
 
 var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     memory: { buffer : memasmFunc }
   });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/deterministic.2asm.js.opt b/binaryen/test/wasm2js/deterministic.2asm.js.opt
--- a/binaryen/test/wasm2js/deterministic.2asm.js.opt
+++ b/binaryen/test/wasm2js/deterministic.2asm.js.opt
@@ -1,27 +1,28 @@
 
-function asmFunc(global, env) {
+function asmFunc(env) {
  var memory = env.memory;
  var buffer = memory.buffer;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   if (4294967252 / HEAPU32[0] | 0) {
    abort()
@@ -39,21 +40,7 @@
 }
 
 var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     memory: { buffer : memasmFunc }
   });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/dot_import.2asm.js b/binaryen/test/wasm2js/dot_import.2asm.js
--- a/binaryen/test/wasm2js/dot_import.2asm.js
+++ b/binaryen/test/wasm2js/dot_import.2asm.js
@@ -1,18 +1,19 @@
 import { ba_se } from 'mod.ule';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var base = env.ba_se;
  function $0() {
   base();
@@ -23,20 +24,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     ba_se
   });
 export var exported = retasmFunc.exported;
diff --git a/binaryen/test/wasm2js/dot_import.2asm.js.opt b/binaryen/test/wasm2js/dot_import.2asm.js.opt
--- a/binaryen/test/wasm2js/dot_import.2asm.js.opt
+++ b/binaryen/test/wasm2js/dot_import.2asm.js.opt
@@ -1,18 +1,19 @@
 import { ba_se } from 'mod.ule';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var base = env.ba_se;
  function $0() {
   base();
@@ -23,20 +24,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     ba_se
   });
 export var exported = retasmFunc.exported;
diff --git a/binaryen/test/wasm2js/dynamicLibrary.2asm.js b/binaryen/test/wasm2js/dynamicLibrary.2asm.js
--- a/binaryen/test/wasm2js/dynamicLibrary.2asm.js
+++ b/binaryen/test/wasm2js/dynamicLibrary.2asm.js
@@ -12,29 +12,54 @@
   return ret;
 }
 
-function asmFunc(global, env) {
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, imports[memoryBase], "ZHluYW1pYyBkYXRh");
+}
+function asmFunc(env) {
  var memory = env.memory;
  var buffer = memory.buffer;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var import$memoryBase = env.memoryBase | 0;
  var import$tableBase = env.tableBase | 0;
  function foo() {
@@ -49,6 +74,8 @@
   
  }
  
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  var FUNCTION_TABLE = Table(new Array(10));
  FUNCTION_TABLE[import$tableBase + 0] = foo;
  FUNCTION_TABLE[import$tableBase + 1] = bar;
@@ -63,41 +90,7 @@
 }
 
 var memasmFunc = new ArrayBuffer(16777216);
-var bufferView = new Uint8Array(memasmFunc);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  base64DecodeToExistingUint8Array(bufferView, memoryBase, "ZHluYW1pYyBkYXRh");
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     memory: { buffer : memasmFunc }
   });
 export var baz = retasmFunc.baz;
diff --git a/binaryen/test/wasm2js/dynamicLibrary.2asm.js.opt b/binaryen/test/wasm2js/dynamicLibrary.2asm.js.opt
--- a/binaryen/test/wasm2js/dynamicLibrary.2asm.js.opt
+++ b/binaryen/test/wasm2js/dynamicLibrary.2asm.js.opt
@@ -12,35 +12,62 @@
   return ret;
 }
 
-function asmFunc(global, env) {
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, imports[memoryBase], "ZHluYW1pYyBkYXRh");
+}
+function asmFunc(env) {
  var memory = env.memory;
  var buffer = memory.buffer;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var import$memoryBase = env.memoryBase | 0;
  var import$tableBase = env.tableBase | 0;
  function foo() {
   
  }
  
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  var FUNCTION_TABLE = Table(new Array(10));
  FUNCTION_TABLE[import$tableBase + 0] = foo;
  FUNCTION_TABLE[import$tableBase + 1] = foo;
@@ -55,41 +82,7 @@
 }
 
 var memasmFunc = new ArrayBuffer(16777216);
-var bufferView = new Uint8Array(memasmFunc);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  base64DecodeToExistingUint8Array(bufferView, memoryBase, "ZHluYW1pYyBkYXRh");
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     memory: { buffer : memasmFunc }
   });
 export var baz = retasmFunc.baz;
diff --git a/binaryen/test/wasm2js/empty_export.2asm.js b/binaryen/test/wasm2js/empty_export.2asm.js
--- a/binaryen/test/wasm2js/empty_export.2asm.js
+++ b/binaryen/test/wasm2js/empty_export.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function foo() {
   
  }
@@ -21,19 +22,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var $ = retasmFunc.$;
diff --git a/binaryen/test/wasm2js/empty_export.2asm.js.opt b/binaryen/test/wasm2js/empty_export.2asm.js.opt
--- a/binaryen/test/wasm2js/empty_export.2asm.js.opt
+++ b/binaryen/test/wasm2js/empty_export.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function foo() {
   
  }
@@ -21,19 +22,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var $ = retasmFunc.$;
diff --git a/binaryen/test/wasm2js/empty_table.2asm.js b/binaryen/test/wasm2js/empty_table.2asm.js
--- a/binaryen/test/wasm2js/empty_table.2asm.js
+++ b/binaryen/test/wasm2js/empty_table.2asm.js
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/emscripten-grow-no.2asm.js b/binaryen/test/wasm2js/emscripten-grow-no.2asm.js
--- a/binaryen/test/wasm2js/emscripten-grow-no.2asm.js
+++ b/binaryen/test/wasm2js/emscripten-grow-no.2asm.js
@@ -1,31 +1,58 @@
-function instantiate(asmLibraryArg, wasmMemory) {
-function asmFunc(global, env) {
+function instantiate(asmLibraryArg) {
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, 1600, "YWJj");
+}
+function asmFunc(env) {
  var memory = env.memory;
  var buffer = memory.buffer;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  // EMSCRIPTEN_START_FUNCS
 ;
  // EMSCRIPTEN_END_FUNCS
 ;
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -45,42 +72,5 @@
  };
 }
 
-var bufferView = new Uint8Array(wasmMemory.buffer);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  base64DecodeToExistingUint8Array(bufferView, 1600, "YWJj");
-return asmFunc({
-    'Int8Array': Int8Array,
-    'Int16Array': Int16Array,
-    'Int32Array': Int32Array,
-    'Uint8Array': Uint8Array,
-    'Uint16Array': Uint16Array,
-    'Uint32Array': Uint32Array,
-    'Float32Array': Float32Array,
-    'Float64Array': Float64Array,
-    'NaN': NaN,
-    'Infinity': Infinity,
-    'Math': Math
-  },
-  asmLibraryArg,
-  wasmMemory.buffer
-)
-
+  return asmFunc(asmLibraryArg);
 }
diff --git a/binaryen/test/wasm2js/emscripten-grow-no.2asm.js.opt b/binaryen/test/wasm2js/emscripten-grow-no.2asm.js.opt
--- a/binaryen/test/wasm2js/emscripten-grow-no.2asm.js.opt
+++ b/binaryen/test/wasm2js/emscripten-grow-no.2asm.js.opt
@@ -1,31 +1,58 @@
-function instantiate(asmLibraryArg, wasmMemory) {
-function asmFunc(global, env) {
+function instantiate(asmLibraryArg) {
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, 1600, "YWJj");
+}
+function asmFunc(env) {
  var memory = env.memory;
  var buffer = memory.buffer;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  // EMSCRIPTEN_START_FUNCS
 ;
  // EMSCRIPTEN_END_FUNCS
 ;
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -45,42 +72,5 @@
  };
 }
 
-var bufferView = new Uint8Array(wasmMemory.buffer);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  base64DecodeToExistingUint8Array(bufferView, 1600, "YWJj");
-return asmFunc({
-    'Int8Array': Int8Array,
-    'Int16Array': Int16Array,
-    'Int32Array': Int32Array,
-    'Uint8Array': Uint8Array,
-    'Uint16Array': Uint16Array,
-    'Uint32Array': Uint32Array,
-    'Float32Array': Float32Array,
-    'Float64Array': Float64Array,
-    'NaN': NaN,
-    'Infinity': Infinity,
-    'Math': Math
-  },
-  asmLibraryArg,
-  wasmMemory.buffer
-)
-
+  return asmFunc(asmLibraryArg);
 }
diff --git a/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js b/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js
--- a/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js
+++ b/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js
@@ -1,32 +1,59 @@
-function instantiate(asmLibraryArg, wasmMemory) {
-function asmFunc(global, env) {
+function instantiate(asmLibraryArg) {
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, 1600, "YWJj");
+}
+function asmFunc(env) {
  var memory = env.memory;
  var buffer = memory.buffer;
  memory.grow = __wasm_memory_grow;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  // EMSCRIPTEN_START_FUNCS
 ;
  // EMSCRIPTEN_END_FUNCS
 ;
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -37,19 +64,19 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
-   memory.buffer = newBuffer;
+   memory.buffer = buffer;
+   bufferView = HEAPU8;
   }
   return oldPages;
  }
@@ -69,42 +96,5 @@
  };
 }
 
-var bufferView = new Uint8Array(wasmMemory.buffer);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  base64DecodeToExistingUint8Array(bufferView, 1600, "YWJj");
-return asmFunc({
-    'Int8Array': Int8Array,
-    'Int16Array': Int16Array,
-    'Int32Array': Int32Array,
-    'Uint8Array': Uint8Array,
-    'Uint16Array': Uint16Array,
-    'Uint32Array': Uint32Array,
-    'Float32Array': Float32Array,
-    'Float64Array': Float64Array,
-    'NaN': NaN,
-    'Infinity': Infinity,
-    'Math': Math
-  },
-  asmLibraryArg,
-  wasmMemory.buffer
-)
-
+  return asmFunc(asmLibraryArg);
 }
diff --git a/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js.opt b/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js.opt
--- a/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js.opt
+++ b/binaryen/test/wasm2js/emscripten-grow-yes.2asm.js.opt
@@ -1,32 +1,59 @@
-function instantiate(asmLibraryArg, wasmMemory) {
-function asmFunc(global, env) {
+function instantiate(asmLibraryArg) {
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, 1600, "YWJj");
+}
+function asmFunc(env) {
  var memory = env.memory;
  var buffer = memory.buffer;
  memory.grow = __wasm_memory_grow;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  // EMSCRIPTEN_START_FUNCS
 ;
  // EMSCRIPTEN_END_FUNCS
 ;
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -37,19 +64,19 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
-   memory.buffer = newBuffer;
+   memory.buffer = buffer;
+   bufferView = HEAPU8;
   }
   return oldPages;
  }
@@ -69,42 +96,5 @@
  };
 }
 
-var bufferView = new Uint8Array(wasmMemory.buffer);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  base64DecodeToExistingUint8Array(bufferView, 1600, "YWJj");
-return asmFunc({
-    'Int8Array': Int8Array,
-    'Int16Array': Int16Array,
-    'Int32Array': Int32Array,
-    'Uint8Array': Uint8Array,
-    'Uint16Array': Uint16Array,
-    'Uint32Array': Uint32Array,
-    'Float32Array': Float32Array,
-    'Float64Array': Float64Array,
-    'NaN': NaN,
-    'Infinity': Infinity,
-    'Math': Math
-  },
-  asmLibraryArg,
-  wasmMemory.buffer
-)
-
+  return asmFunc(asmLibraryArg);
 }
diff --git a/binaryen/test/wasm2js/emscripten.2asm.js b/binaryen/test/wasm2js/emscripten.2asm.js
--- a/binaryen/test/wasm2js/emscripten.2asm.js
+++ b/binaryen/test/wasm2js/emscripten.2asm.js
@@ -1,28 +1,53 @@
-function instantiate(asmLibraryArg, wasmMemory) {
-function asmFunc(global, env) {
- var memory = env.memory;
- var buffer = memory.buffer;
+function instantiate(asmLibraryArg) {
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, 1024, "aGVsbG8sIHdvcmxkIQoAAJwMAAAtKyAgIDBYMHgAKG51bGwpAAAAAAAAAAAAAAAAEQAKABEREQAAAAAFAAAAAAAACQAAAAALAAAAAAAAAAARAA8KERERAwoHAAETCQsLAAAJBgsAAAsABhEAAAAREREAAAAAAAAAAAAAAAAAAAAACwAAAAAAAAAAEQAKChEREQAKAAACAAkLAAAACQALAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAwAAAAADAAAAAAJDAAAAAAADAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAANAAAABA0AAAAACQ4AAAAAAA4AAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAADwAAAAAPAAAAAAkQAAAAAAAQAAAQAAASAAAAEhISAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAASEhIAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAAAAAAAAAAKAAAAAAoAAAAACQsAAAAAAAsAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAADAAAAAAMAAAAAAkMAAAAAAAMAAAMAAAwMTIzNDU2Nzg5QUJDREVGLTBYKzBYIDBYLTB4KzB4IDB4AGluZgBJTkYAbmFuAE5BTgAuAA==");
+  base64DecodeToExistingUint8Array(bufferView, 1600, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
+}
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(16777216);
  var FUNCTION_TABLE = env.table;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var syscall$6 = env.__syscall6;
  var syscall$54 = env.__syscall54;
  // EMSCRIPTEN_START_FUNCS
@@ -186,6 +211,8 @@
  
  // EMSCRIPTEN_END_FUNCS
 ;
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  FUNCTION_TABLE[1] = foo;
  FUNCTION_TABLE[2] = bar;
  FUNCTION_TABLE[3] = tabled;
@@ -204,43 +231,5 @@
  };
 }
 
-var bufferView = new Uint8Array(wasmMemory.buffer);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  base64DecodeToExistingUint8Array(bufferView, 1024, "aGVsbG8sIHdvcmxkIQoAAJwMAAAtKyAgIDBYMHgAKG51bGwpAAAAAAAAAAAAAAAAEQAKABEREQAAAAAFAAAAAAAACQAAAAALAAAAAAAAAAARAA8KERERAwoHAAETCQsLAAAJBgsAAAsABhEAAAAREREAAAAAAAAAAAAAAAAAAAAACwAAAAAAAAAAEQAKChEREQAKAAACAAkLAAAACQALAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAwAAAAADAAAAAAJDAAAAAAADAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAANAAAABA0AAAAACQ4AAAAAAA4AAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAADwAAAAAPAAAAAAkQAAAAAAAQAAAQAAASAAAAEhISAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAASEhIAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAAAAAAAAAAKAAAAAAoAAAAACQsAAAAAAAsAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAADAAAAAAMAAAAAAkMAAAAAAAMAAAMAAAwMTIzNDU2Nzg5QUJDREVGLTBYKzBYIDBYLTB4KzB4IDB4AGluZgBJTkYAbmFuAE5BTgAuAA==");
-base64DecodeToExistingUint8Array(bufferView, 1600, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
-return asmFunc({
-    'Int8Array': Int8Array,
-    'Int16Array': Int16Array,
-    'Int32Array': Int32Array,
-    'Uint8Array': Uint8Array,
-    'Uint16Array': Uint16Array,
-    'Uint32Array': Uint32Array,
-    'Float32Array': Float32Array,
-    'Float64Array': Float64Array,
-    'NaN': NaN,
-    'Infinity': Infinity,
-    'Math': Math
-  },
-  asmLibraryArg,
-  wasmMemory.buffer
-)
-
+  return asmFunc(asmLibraryArg);
 }
diff --git a/binaryen/test/wasm2js/emscripten.2asm.js.opt b/binaryen/test/wasm2js/emscripten.2asm.js.opt
--- a/binaryen/test/wasm2js/emscripten.2asm.js.opt
+++ b/binaryen/test/wasm2js/emscripten.2asm.js.opt
@@ -1,28 +1,65 @@
-function instantiate(asmLibraryArg, wasmMemory) {
-function asmFunc(global, env) {
- var memory = env.memory;
- var buffer = memory.buffer;
+function instantiate(asmLibraryArg) {
+  var bufferView;
+  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
+  for (var i = 25; i >= 0; --i) {
+    base64ReverseLookup[48+i] = 52+i; // '0-9'
+    base64ReverseLookup[65+i] = i; // 'A-Z'
+    base64ReverseLookup[97+i] = 26+i; // 'a-z'
+  }
+  base64ReverseLookup[43] = 62; // '+'
+  base64ReverseLookup[47] = 63; // '/'
+  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
+  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
+    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
+    for (; i < bLength; i += 4) {
+      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
+      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
+      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
+      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
+      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
+    }
+    return uint8Array;
+  }
+function initActiveSegments(imports) {
+  base64DecodeToExistingUint8Array(bufferView, 1024, "aGVsbG8sIHdvcmxkIQoAAJwMAAAtKyAgIDBYMHgAKG51bGwp");
+  base64DecodeToExistingUint8Array(bufferView, 1072, "EQAKABEREQAAAAAFAAAAAAAACQAAAAALAAAAAAAAAAARAA8KERERAwoHAAETCQsLAAAJBgsAAAsABhEAAAARERE=");
+  base64DecodeToExistingUint8Array(bufferView, 1153, "CwAAAAAAAAAAEQAKChEREQAKAAACAAkLAAAACQALAAAL");
+  base64DecodeToExistingUint8Array(bufferView, 1211, "DA==");
+  base64DecodeToExistingUint8Array(bufferView, 1223, "DAAAAAAMAAAAAAkMAAAAAAAMAAAM");
+  base64DecodeToExistingUint8Array(bufferView, 1269, "Dg==");
+  base64DecodeToExistingUint8Array(bufferView, 1281, "DQAAAAQNAAAAAAkOAAAAAAAOAAAO");
+  base64DecodeToExistingUint8Array(bufferView, 1327, "EA==");
+  base64DecodeToExistingUint8Array(bufferView, 1339, "DwAAAAAPAAAAAAkQAAAAAAAQAAAQAAASAAAAEhIS");
+  base64DecodeToExistingUint8Array(bufferView, 1394, "EgAAABISEgAAAAAAAAk=");
+  base64DecodeToExistingUint8Array(bufferView, 1443, "Cw==");
+  base64DecodeToExistingUint8Array(bufferView, 1455, "CgAAAAAKAAAAAAkLAAAAAAALAAAL");
+  base64DecodeToExistingUint8Array(bufferView, 1501, "DA==");
+  base64DecodeToExistingUint8Array(bufferView, 1513, "DAAAAAAMAAAAAAkMAAAAAAAMAAAMAAAwMTIzNDU2Nzg5QUJDREVGLTBYKzBYIDBYLTB4KzB4IDB4AGluZgBJTkYAbmFuAE5BTgAu");
+}
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(16777216);
  var FUNCTION_TABLE = env.table;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var syscall$6 = env.__syscall6;
  var syscall$54 = env.__syscall54;
  // EMSCRIPTEN_START_FUNCS
@@ -167,6 +204,8 @@
  
  // EMSCRIPTEN_END_FUNCS
 ;
+ bufferView = HEAPU8;
+ initActiveSegments(env);
  FUNCTION_TABLE[1] = foo;
  FUNCTION_TABLE[2] = bar;
  FUNCTION_TABLE[3] = internal;
@@ -185,55 +224,5 @@
  };
 }
 
-var bufferView = new Uint8Array(wasmMemory.buffer);
-for (var base64ReverseLookup = new Uint8Array(123/*'z'+1*/), i = 25; i >= 0; --i) {
-    base64ReverseLookup[48+i] = 52+i; // '0-9'
-    base64ReverseLookup[65+i] = i; // 'A-Z'
-    base64ReverseLookup[97+i] = 26+i; // 'a-z'
-  }
-  base64ReverseLookup[43] = 62; // '+'
-  base64ReverseLookup[47] = 63; // '/'
-  /** @noinline Inlining this function would mean expanding the base64 string 4x times in the source code, which Closure seems to be happy to do. */
-  function base64DecodeToExistingUint8Array(uint8Array, offset, b64) {
-    var b1, b2, i = 0, j = offset, bLength = b64.length, end = offset + (bLength*3>>2) - (b64[bLength-2] == '=') - (b64[bLength-1] == '=');
-    for (; i < bLength; i += 4) {
-      b1 = base64ReverseLookup[b64.charCodeAt(i+1)];
-      b2 = base64ReverseLookup[b64.charCodeAt(i+2)];
-      uint8Array[j++] = base64ReverseLookup[b64.charCodeAt(i)] << 2 | b1 >> 4;
-      if (j < end) uint8Array[j++] = b1 << 4 | b2 >> 2;
-      if (j < end) uint8Array[j++] = b2 << 6 | base64ReverseLookup[b64.charCodeAt(i+3)];
-    }
-    return uint8Array; 
-  }
-  base64DecodeToExistingUint8Array(bufferView, 1024, "aGVsbG8sIHdvcmxkIQoAAJwMAAAtKyAgIDBYMHgAKG51bGwp");
-base64DecodeToExistingUint8Array(bufferView, 1072, "EQAKABEREQAAAAAFAAAAAAAACQAAAAALAAAAAAAAAAARAA8KERERAwoHAAETCQsLAAAJBgsAAAsABhEAAAARERE=");
-base64DecodeToExistingUint8Array(bufferView, 1153, "CwAAAAAAAAAAEQAKChEREQAKAAACAAkLAAAACQALAAAL");
-base64DecodeToExistingUint8Array(bufferView, 1211, "DA==");
-base64DecodeToExistingUint8Array(bufferView, 1223, "DAAAAAAMAAAAAAkMAAAAAAAMAAAM");
-base64DecodeToExistingUint8Array(bufferView, 1269, "Dg==");
-base64DecodeToExistingUint8Array(bufferView, 1281, "DQAAAAQNAAAAAAkOAAAAAAAOAAAO");
-base64DecodeToExistingUint8Array(bufferView, 1327, "EA==");
-base64DecodeToExistingUint8Array(bufferView, 1339, "DwAAAAAPAAAAAAkQAAAAAAAQAAAQAAASAAAAEhIS");
-base64DecodeToExistingUint8Array(bufferView, 1394, "EgAAABISEgAAAAAAAAk=");
-base64DecodeToExistingUint8Array(bufferView, 1443, "Cw==");
-base64DecodeToExistingUint8Array(bufferView, 1455, "CgAAAAAKAAAAAAkLAAAAAAALAAAL");
-base64DecodeToExistingUint8Array(bufferView, 1501, "DA==");
-base64DecodeToExistingUint8Array(bufferView, 1513, "DAAAAAAMAAAAAAkMAAAAAAAMAAAMAAAwMTIzNDU2Nzg5QUJDREVGLTBYKzBYIDBYLTB4KzB4IDB4AGluZgBJTkYAbmFuAE5BTgAu");
-return asmFunc({
-    'Int8Array': Int8Array,
-    'Int16Array': Int16Array,
-    'Int32Array': Int32Array,
-    'Uint8Array': Uint8Array,
-    'Uint16Array': Uint16Array,
-    'Uint32Array': Uint32Array,
-    'Float32Array': Float32Array,
-    'Float64Array': Float64Array,
-    'NaN': NaN,
-    'Infinity': Infinity,
-    'Math': Math
-  },
-  asmLibraryArg,
-  wasmMemory.buffer
-)
-
+  return asmFunc(asmLibraryArg);
 }
diff --git a/binaryen/test/wasm2js/emscripten.wast b/binaryen/test/wasm2js/emscripten.wast
--- a/binaryen/test/wasm2js/emscripten.wast
+++ b/binaryen/test/wasm2js/emscripten.wast
@@ -1,6 +1,6 @@
 (module
  (type $0 (func))
- (import "env" "memory" (memory $8 256 256))
+ (memory $8 256 256)
  (data (i32.const 1024) "hello, world!\n\00\00\9c\0c\00\00-+   0X0x\00(null)\00\00\00\00\00\00\00\00\00\00\00\00\11\00\n\00\11\11\11\00\00\00\00\05\00\00\00\00\00\00\t\00\00\00\00\0b\00\00\00\00\00\00\00\00\11\00\0f\n\11\11\11\03\n\07\00\01\13\t\0b\0b\00\00\t\06\0b\00\00\0b\00\06\11\00\00\00\11\11\11\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0b\00\00\00\00\00\00\00\00\11\00\n\n\11\11\11\00\n\00\00\02\00\t\0b\00\00\00\t\00\0b\00\00\0b\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\0c\00\00\00\00\t\0c\00\00\00\00\00\0c\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0e\00\00\00\00\00\00\00\00\00\00\00\0d\00\00\00\04\0d\00\00\00\00\t\0e\00\00\00\00\00\0e\00\00\0e\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\10\00\00\00\00\00\00\00\00\00\00\00\0f\00\00\00\00\0f\00\00\00\00\t\10\00\00\00\00\00\10\00\00\10\00\00\12\00\00\00\12\12\12\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\12\00\00\00\12\12\12\00\00\00\00\00\00\t\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0b\00\00\00\00\00\00\00\00\00\00\00\n\00\00\00\00\n\00\00\00\00\t\0b\00\00\00\00\00\0b\00\00\0b\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\00\00\00\00\00\00\00\0c\00\00\00\00\0c\00\00\00\00\t\0c\00\00\00\00\00\0c\00\00\0c\00\000123456789ABCDEF-0X+0X 0X-0x+0x 0x\00inf\00INF\00nan\00NAN\00.\00")
  (data (i32.const 1600) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
  (import "env" "table" (table $timport$9 7 funcref))
diff --git a/binaryen/test/wasm2js/endianness.2asm.js b/binaryen/test/wasm2js/endianness.2asm.js
--- a/binaryen/test/wasm2js/endianness.2asm.js
+++ b/binaryen/test/wasm2js/endianness.2asm.js
@@ -1,5 +1,6 @@
 import { setTempRet0 } from 'env';
 
+  var bufferView;
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -30,27 +31,29 @@
     return f32ScratchView[2];
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function i16_store_little(address, value) {
@@ -649,6 +652,7 @@
   return $2 | 0;
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -659,18 +663,18 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
+   bufferView = HEAPU8;
   }
   return oldPages;
  }
@@ -696,26 +700,9 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
-  },
-  memasmFunc
-);
+  });
 export var i32_load16_s = retasmFunc.i32_load16_s;
 export var i32_load16_u = retasmFunc.i32_load16_u;
 export var i32_load = retasmFunc.i32_load;
diff --git a/binaryen/test/wasm2js/excess_fallthrough.2asm.js b/binaryen/test/wasm2js/excess_fallthrough.2asm.js
--- a/binaryen/test/wasm2js/excess_fallthrough.2asm.js
+++ b/binaryen/test/wasm2js/excess_fallthrough.2asm.js
@@ -1,37 +1,40 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function bar() {
   
  }
  
  function foo($0) {
   $0 = $0 | 0;
-  label$5 : {
-   bar();
-   block : {
-    switch (123 | 0) {
-    case 0:
-     bar();
-     break;
-    default:
-     break label$5;
-    };
+  label$4 : while (1) {
+   label$5 : {
+    bar();
+    block : {
+     switch (123 | 0) {
+     case 0:
+      bar();
+      break;
+     default:
+      break label$5;
+     };
+    }
+    return;
    }
-   return;
-  }
-  abort();
+   abort();
+  };
  }
  
  return {
@@ -39,19 +42,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/excess_fallthrough.2asm.js.opt b/binaryen/test/wasm2js/excess_fallthrough.2asm.js.opt
--- a/binaryen/test/wasm2js/excess_fallthrough.2asm.js.opt
+++ b/binaryen/test/wasm2js/excess_fallthrough.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function foo($0) {
   $0 = $0 | 0;
   abort();
@@ -22,19 +23,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/f32.2asm.js b/binaryen/test/wasm2js/f32.2asm.js
--- a/binaryen/test/wasm2js/f32.2asm.js
+++ b/binaryen/test/wasm2js/f32.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(x, y) {
   x = Math_fround(x);
   y = Math_fround(y);
@@ -65,7 +66,7 @@
  
  function $9(x) {
   x = Math_fround(x);
-  return Math_fround(Math_fround(__wasm_trunc_f32(Math_fround(x))));
+  return Math_fround(Math_fround(Math_trunc(x)));
  }
  
  function $10(x) {
@@ -91,11 +92,6 @@
   return Math_fround(var$1);
  }
  
- function __wasm_trunc_f32(var$0) {
-  var$0 = Math_fround(var$0);
-  return Math_fround(var$0 < Math_fround(0.0) ? Math_fround(Math_ceil(var$0)) : Math_fround(Math_floor(var$0)));
- }
- 
  return {
   "add": $0, 
   "sub": $1, 
@@ -111,20 +107,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var add = retasmFunc.add;
 export var sub = retasmFunc.sub;
diff --git a/binaryen/test/wasm2js/f32_cmp.2asm.js b/binaryen/test/wasm2js/f32_cmp.2asm.js
--- a/binaryen/test/wasm2js/f32_cmp.2asm.js
+++ b/binaryen/test/wasm2js/f32_cmp.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(x, y) {
   x = Math_fround(x);
   y = Math_fround(y);
@@ -58,20 +59,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var eq = retasmFunc.eq;
 export var ne = retasmFunc.ne;
diff --git a/binaryen/test/wasm2js/f64_cmp.2asm.js b/binaryen/test/wasm2js/f64_cmp.2asm.js
--- a/binaryen/test/wasm2js/f64_cmp.2asm.js
+++ b/binaryen/test/wasm2js/f64_cmp.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(x, y) {
   x = +x;
   y = +y;
@@ -58,20 +59,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var eq = retasmFunc.eq;
 export var ne = retasmFunc.ne;
diff --git a/binaryen/test/wasm2js/fac.2asm.js b/binaryen/test/wasm2js/fac.2asm.js
--- a/binaryen/test/wasm2js/fac.2asm.js
+++ b/binaryen/test/wasm2js/fac.2asm.js
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0($0_1, $0$hi) {
@@ -573,20 +574,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var fac_rec = retasmFunc.fac_rec;
diff --git a/binaryen/test/wasm2js/float-ops.2asm.js b/binaryen/test/wasm2js/float-ops.2asm.js
--- a/binaryen/test/wasm2js/float-ops.2asm.js
+++ b/binaryen/test/wasm2js/float-ops.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0, $1_1) {
   $0 = Math_fround($0);
   $1_1 = Math_fround($1_1);
@@ -504,20 +505,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var f32_add = retasmFunc.f32_add;
 export var f32_sub = retasmFunc.f32_sub;
diff --git a/binaryen/test/wasm2js/float-ops.2asm.js.opt b/binaryen/test/wasm2js/float-ops.2asm.js.opt
--- a/binaryen/test/wasm2js/float-ops.2asm.js.opt
+++ b/binaryen/test/wasm2js/float-ops.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0, $1_1) {
   $0 = Math_fround($0);
   $1_1 = Math_fround($1_1);
@@ -238,12 +239,12 @@
  
  function $47($0) {
   $0 = Math_fround($0);
-  return !(~~$0 >>> 0 | (Math_fround(Math_abs($0)) >= Math_fround(1.0) ? ($0 > Math_fround(0.0) ? ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround($0 / Math_fround(4294967296.0)))), Math_fround(4294967296.0))) >>> 0 : ~~Math_fround(Math_ceil(Math_fround(Math_fround($0 - Math_fround(~~$0 >>> 0 >>> 0)) / Math_fround(4294967296.0)))) >>> 0) : 0)) | 0;
+  return !(~~$0 >>> 0 | (Math_fround(Math_abs($0)) >= Math_fround(1.0) ? ($0 > Math_fround(0.0) ? ~~Math_fround(Math_min(Math_fround(Math_floor(Math_fround($0 * Math_fround(2.3283064365386963e-10)))), Math_fround(4294967296.0))) >>> 0 : ~~Math_fround(Math_ceil(Math_fround(Math_fround($0 - Math_fround(~~$0 >>> 0 >>> 0)) * Math_fround(2.3283064365386963e-10)))) >>> 0) : 0)) | 0;
  }
  
  function $48($0) {
   $0 = +$0;
-  return !(~~$0 >>> 0 | (Math_abs($0) >= 1.0 ? ($0 > 0.0 ? ~~Math_min(Math_floor($0 / 4294967296.0), 4294967295.0) >>> 0 : ~~Math_ceil(($0 - +(~~$0 >>> 0 >>> 0)) / 4294967296.0) >>> 0) : 0)) | 0;
+  return !(~~$0 >>> 0 | (Math_abs($0) >= 1.0 ? ($0 > 0.0 ? ~~Math_min(Math_floor($0 * 2.3283064365386963e-10), 4294967295.0) >>> 0 : ~~Math_ceil(($0 - +(~~$0 >>> 0 >>> 0)) * 2.3283064365386963e-10) >>> 0) : 0)) | 0;
  }
  
  function legalstub$43($0, $1_1) {
@@ -314,20 +315,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var f32_add = retasmFunc.f32_add;
 export var f32_sub = retasmFunc.f32_sub;
diff --git a/binaryen/test/wasm2js/float_literals-modified.2asm.js b/binaryen/test/wasm2js/float_literals-modified.2asm.js
--- a/binaryen/test/wasm2js/float_literals-modified.2asm.js
+++ b/binaryen/test/wasm2js/float_literals-modified.2asm.js
@@ -18,19 +18,20 @@
     f32ScratchView[2] = value;
   }
       
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0() {
@@ -1147,20 +1148,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var f32_nan = retasmFunc.f32_nan;
diff --git a/binaryen/test/wasm2js/float_literals-modified.2asm.js.opt b/binaryen/test/wasm2js/float_literals-modified.2asm.js.opt
--- a/binaryen/test/wasm2js/float_literals-modified.2asm.js.opt
+++ b/binaryen/test/wasm2js/float_literals-modified.2asm.js.opt
@@ -14,19 +14,20 @@
     f64ScratchView[0] = value;
   }
       
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0() {
@@ -363,20 +364,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var f32_nan = retasmFunc.f32_nan;
diff --git a/binaryen/test/wasm2js/float_misc.2asm.js b/binaryen/test/wasm2js/float_misc.2asm.js
--- a/binaryen/test/wasm2js/float_misc.2asm.js
+++ b/binaryen/test/wasm2js/float_misc.2asm.js
@@ -29,19 +29,20 @@
     f32ScratchView[2] = value;
   }
       
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(x, y) {
   x = Math_fround(x);
   y = Math_fround(y);
@@ -99,7 +100,7 @@
  
  function $10(x) {
   x = Math_fround(x);
-  return Math_fround(Math_fround(__wasm_trunc_f32(Math_fround(x))));
+  return Math_fround(Math_fround(Math_trunc(x)));
  }
  
  function $11(x) {
@@ -200,7 +201,7 @@
  
  function $24(x) {
   x = +x;
-  return +(+__wasm_trunc_f64(+x));
+  return +Math_trunc(x);
  }
  
  function $25(x) {
@@ -256,16 +257,6 @@
   return +var$1;
  }
  
- function __wasm_trunc_f32(var$0) {
-  var$0 = Math_fround(var$0);
-  return Math_fround(var$0 < Math_fround(0.0) ? Math_fround(Math_ceil(var$0)) : Math_fround(Math_floor(var$0)));
- }
- 
- function __wasm_trunc_f64(var$0) {
-  var$0 = +var$0;
-  return +(var$0 < 0.0 ? Math_ceil(var$0) : Math_floor(var$0));
- }
- 
  return {
   "f32_add": $0, 
   "f32_sub": $1, 
@@ -298,20 +289,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var f32_add = retasmFunc.f32_add;
 export var f32_sub = retasmFunc.f32_sub;
diff --git a/binaryen/test/wasm2js/forward.2asm.js b/binaryen/test/wasm2js/forward.2asm.js
--- a/binaryen/test/wasm2js/forward.2asm.js
+++ b/binaryen/test/wasm2js/forward.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function even(n) {
   n = n | 0;
   var $10 = 0;
@@ -40,20 +41,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var even = retasmFunc.even;
 export var odd = retasmFunc.odd;
diff --git a/binaryen/test/wasm2js/func-ptr-offset.2asm.js b/binaryen/test/wasm2js/func-ptr-offset.2asm.js
--- a/binaryen/test/wasm2js/func-ptr-offset.2asm.js
+++ b/binaryen/test/wasm2js/func-ptr-offset.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function t1() {
   return 1 | 0;
  }
@@ -35,19 +36,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var call = retasmFunc.call;
diff --git a/binaryen/test/wasm2js/func-ptr-offset.2asm.js.opt b/binaryen/test/wasm2js/func-ptr-offset.2asm.js.opt
--- a/binaryen/test/wasm2js/func-ptr-offset.2asm.js.opt
+++ b/binaryen/test/wasm2js/func-ptr-offset.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function t1() {
   return 1;
  }
@@ -35,19 +36,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var call = retasmFunc.call;
diff --git a/binaryen/test/wasm2js/func_ptrs.2asm.js b/binaryen/test/wasm2js/func_ptrs.2asm.js
--- a/binaryen/test/wasm2js/func_ptrs.2asm.js
+++ b/binaryen/test/wasm2js/func_ptrs.2asm.js
@@ -1,18 +1,19 @@
 import { print_i32 } from 'spectest';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var print = env.print_i32;
  function $3() {
   return 13 | 0;
@@ -41,20 +42,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     print_i32
   });
 export var one = retasmFunc.one;
@@ -62,19 +50,20 @@
 export var three = retasmFunc.three;
 export var four = retasmFunc.four;
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function t1() {
   return 1 | 0;
  }
@@ -112,37 +101,25 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var callt = retasmFunc.callt;
 export var callu = retasmFunc.callu;
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function t1() {
   return 1 | 0;
  }
@@ -162,19 +139,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var callt = retasmFunc.callt;
diff --git a/binaryen/test/wasm2js/get-set-local.2asm.js b/binaryen/test/wasm2js/get-set-local.2asm.js
--- a/binaryen/test/wasm2js/get-set-local.2asm.js
+++ b/binaryen/test/wasm2js/get-set-local.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0, r, r$hi) {
   $0 = $0 | 0;
   r = r | 0;
@@ -60,19 +61,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var check_extend_ui32 = retasmFunc.check_extend_ui32;
diff --git a/binaryen/test/wasm2js/get-set-local.2asm.js.opt b/binaryen/test/wasm2js/get-set-local.2asm.js.opt
--- a/binaryen/test/wasm2js/get-set-local.2asm.js.opt
+++ b/binaryen/test/wasm2js/get-set-local.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function legalstub$1($0, $1, $2) {
   return !$2 & ($0 | 0) == ($1 | 0);
  }
@@ -21,19 +22,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var check_extend_ui32 = retasmFunc.check_extend_ui32;
diff --git a/binaryen/test/wasm2js/get_local.2asm.js b/binaryen/test/wasm2js/get_local.2asm.js
--- a/binaryen/test/wasm2js/get_local.2asm.js
+++ b/binaryen/test/wasm2js/get_local.2asm.js
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0() {
@@ -240,20 +241,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var type_local_i32 = retasmFunc.type_local_i32;
diff --git a/binaryen/test/wasm2js/global_i64.2asm.js b/binaryen/test/wasm2js/global_i64.2asm.js
--- a/binaryen/test/wasm2js/global_i64.2asm.js
+++ b/binaryen/test/wasm2js/global_i64.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var f = -1412567121;
  var f$hi = 305419896;
  function call($0, $0$hi) {
@@ -33,19 +34,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var exp = retasmFunc.exp;
diff --git a/binaryen/test/wasm2js/global_i64.2asm.js.opt b/binaryen/test/wasm2js/global_i64.2asm.js.opt
--- a/binaryen/test/wasm2js/global_i64.2asm.js.opt
+++ b/binaryen/test/wasm2js/global_i64.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1() {
   
  }
@@ -21,19 +22,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var exp = retasmFunc.exp;
diff --git a/binaryen/test/wasm2js/grow-memory-tricky.2asm.js b/binaryen/test/wasm2js/grow-memory-tricky.2asm.js
--- a/binaryen/test/wasm2js/grow-memory-tricky.2asm.js
+++ b/binaryen/test/wasm2js/grow-memory-tricky.2asm.js
@@ -1,25 +1,27 @@
 
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
   (wasm2js_i32$0 = 0, wasm2js_i32$1 = __wasm_memory_grow(1 | 0)), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$1;
@@ -46,17 +48,16 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
   }
   return oldPages;
@@ -79,25 +80,8 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var memory = retasmFunc.memory;
 export var f1 = retasmFunc.f1;
 export var f2 = retasmFunc.f2;
diff --git a/binaryen/test/wasm2js/grow-memory-tricky.2asm.js.opt b/binaryen/test/wasm2js/grow-memory-tricky.2asm.js.opt
--- a/binaryen/test/wasm2js/grow-memory-tricky.2asm.js.opt
+++ b/binaryen/test/wasm2js/grow-memory-tricky.2asm.js.opt
@@ -1,25 +1,27 @@
 
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0;
   (wasm2js_i32$0 = 0, wasm2js_i32$1 = __wasm_memory_grow(1)), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$1;
@@ -36,17 +38,16 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
   }
   return oldPages;
@@ -69,25 +70,8 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var memory = retasmFunc.memory;
 export var f1 = retasmFunc.f1;
 export var f2 = retasmFunc.f2;
diff --git a/binaryen/test/wasm2js/grow_memory.2asm.js b/binaryen/test/wasm2js/grow_memory.2asm.js
--- a/binaryen/test/wasm2js/grow_memory.2asm.js
+++ b/binaryen/test/wasm2js/grow_memory.2asm.js
@@ -1,25 +1,27 @@
 
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(var$0) {
   var$0 = var$0 | 0;
   return __wasm_memory_grow(var$0 | 0) | 0;
@@ -39,17 +41,16 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
   }
   return oldPages;
@@ -72,25 +73,8 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var memory = retasmFunc.memory;
 export var grow = retasmFunc.grow;
 export var current = retasmFunc.current;
diff --git a/binaryen/test/wasm2js/i32.2asm.js b/binaryen/test/wasm2js/i32.2asm.js
--- a/binaryen/test/wasm2js/i32.2asm.js
+++ b/binaryen/test/wasm2js/i32.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(x, y) {
   x = x | 0;
   y = y | 0;
@@ -258,20 +259,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var add = retasmFunc.add;
 export var sub = retasmFunc.sub;
diff --git a/binaryen/test/wasm2js/i64-add-sub.2asm.js b/binaryen/test/wasm2js/i64-add-sub.2asm.js
--- a/binaryen/test/wasm2js/i64-add-sub.2asm.js
+++ b/binaryen/test/wasm2js/i64-add-sub.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0, $0$hi, $1_1, $1$hi, r, r$hi) {
   $0 = $0 | 0;
   $0$hi = $0$hi | 0;
@@ -229,20 +230,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var check_add_i64 = retasmFunc.check_add_i64;
 export var check_sub_i64 = retasmFunc.check_sub_i64;
diff --git a/binaryen/test/wasm2js/i64-add-sub.2asm.js.opt b/binaryen/test/wasm2js/i64-add-sub.2asm.js.opt
--- a/binaryen/test/wasm2js/i64-add-sub.2asm.js.opt
+++ b/binaryen/test/wasm2js/i64-add-sub.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0, $1_1, $2, $3, $4, $5) {
   $0 = $0 | 0;
   $1_1 = $1_1 | 0;
@@ -21,9 +22,7 @@
   $5 = $5 | 0;
   $1_1 = $1_1 + $3 | 0;
   $0 = $0 + $2 | 0;
-  if ($0 >>> 0 < $2 >>> 0) {
-   $1_1 = $1_1 + 1 | 0
-  }
+  $1_1 = $2 >>> 0 > $0 >>> 0 ? $1_1 + 1 | 0 : $1_1;
   return ($0 | 0) == ($4 | 0) & ($1_1 | 0) == ($5 | 0);
  }
  
@@ -41,20 +40,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var check_add_i64 = retasmFunc.check_add_i64;
 export var check_sub_i64 = retasmFunc.check_sub_i64;
diff --git a/binaryen/test/wasm2js/i64-ctz.2asm.js b/binaryen/test/wasm2js/i64-ctz.2asm.js
--- a/binaryen/test/wasm2js/i64-ctz.2asm.js
+++ b/binaryen/test/wasm2js/i64-ctz.2asm.js
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function popcnt64($0, $0$hi) {
@@ -232,20 +233,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var a = retasmFunc.a;
diff --git a/binaryen/test/wasm2js/i64-ctz.2asm.js.opt b/binaryen/test/wasm2js/i64-ctz.2asm.js.opt
--- a/binaryen/test/wasm2js/i64-ctz.2asm.js.opt
+++ b/binaryen/test/wasm2js/i64-ctz.2asm.js.opt
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function legalstub$popcnt64($0, $1) {
@@ -30,16 +31,14 @@
  function __wasm_ctz_i64($0, $1) {
   var $2 = 0, $3 = 0;
   if ($0 | $1) {
-   $3 = $1 + -1 | 0;
-   $2 = $0 + -1 | 0;
-   if (($2 | 0) != -1) {
-    $3 = $3 + 1 | 0
-   }
-   $2 = Math_clz32($0 ^ $2) + 32 | 0;
-   $0 = Math_clz32($1 ^ $3);
-   $0 = ($0 | 0) == 32 ? $2 : $0;
+   $2 = $1 - 1 | 0;
+   $3 = $0 - 1 | 0;
+   $2 = ($3 | 0) != -1 ? $2 + 1 | 0 : $2;
+   $3 = Math_clz32($0 ^ $3) + 32 | 0;
+   $0 = Math_clz32($1 ^ $2);
+   $0 = ($0 | 0) == 32 ? $3 : $0;
    $1 = 63 - $0 | 0;
-   i64toi32_i32$HIGH_BITS = 0 - (63 < $0 >>> 0) | 0;
+   i64toi32_i32$HIGH_BITS = 0 - ($0 >>> 0 > 63) | 0;
    return $1;
   }
   i64toi32_i32$HIGH_BITS = 0;
@@ -49,17 +48,15 @@
  function __wasm_popcnt_i64($0, $1) {
   var $2 = 0, $3 = 0, $4 = 0, $5 = 0;
   while (1) {
-   $5 = $3;
-   $2 = $4;
+   $5 = $4;
+   $2 = $3;
    if ($0 | $1) {
     $2 = $0;
     $0 = $2 - 1 & $2;
     $1 = $1 - ($2 >>> 0 < 1) & $1;
-    $2 = $3 + 1 | 0;
-    if ($2 >>> 0 < 1) {
-     $4 = $4 + 1 | 0
-    }
-    $3 = $2;
+    $2 = $4 + 1 | 0;
+    $3 = $2 >>> 0 < 1 ? $3 + 1 | 0 : $3;
+    $4 = $2;
     continue;
    }
    break;
@@ -74,20 +71,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var a = retasmFunc.a;
diff --git a/binaryen/test/wasm2js/i64-lowering.2asm.js b/binaryen/test/wasm2js/i64-lowering.2asm.js
--- a/binaryen/test/wasm2js/i64-lowering.2asm.js
+++ b/binaryen/test/wasm2js/i64-lowering.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0, $0$hi, $1_1, $1$hi) {
   $0 = $0 | 0;
   $0$hi = $0$hi | 0;
@@ -788,20 +789,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var eq_i64 = retasmFunc.eq_i64;
 export var ne_i64 = retasmFunc.ne_i64;
diff --git a/binaryen/test/wasm2js/i64-lowering.2asm.js.opt b/binaryen/test/wasm2js/i64-lowering.2asm.js.opt
--- a/binaryen/test/wasm2js/i64-lowering.2asm.js.opt
+++ b/binaryen/test/wasm2js/i64-lowering.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function legalstub$1($0, $1, $2, $3) {
   return ($0 | 0) == ($2 | 0) & ($1 | 0) == ($3 | 0);
  }
@@ -66,20 +67,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var eq_i64 = retasmFunc.eq_i64;
 export var ne_i64 = retasmFunc.ne_i64;
diff --git a/binaryen/test/wasm2js/i64-rotate.2asm.js b/binaryen/test/wasm2js/i64-rotate.2asm.js
--- a/binaryen/test/wasm2js/i64-rotate.2asm.js
+++ b/binaryen/test/wasm2js/i64-rotate.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var i64toi32_i32$HIGH_BITS = 0;
  function $1($0, $0$hi, $1_1, $1$hi, $2_1, $2$hi) {
   $0 = $0 | 0;
@@ -441,20 +442,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var rotl = retasmFunc.rotl;
 export var rotr = retasmFunc.rotr;
diff --git a/binaryen/test/wasm2js/i64-rotate.2asm.js.opt b/binaryen/test/wasm2js/i64-rotate.2asm.js.opt
--- a/binaryen/test/wasm2js/i64-rotate.2asm.js.opt
+++ b/binaryen/test/wasm2js/i64-rotate.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var i64toi32_i32$HIGH_BITS = 0;
  function legalstub$1($0, $1, $2, $3, $4, $5) {
   return (__wasm_rotl_i64($0, $1, $2) | 0) == ($4 | 0) & ($5 | 0) == (i64toi32_i32$HIGH_BITS | 0);
@@ -26,7 +27,7 @@
   $6 = $2 & 63;
   $5 = $6;
   $3 = $5 & 31;
-  if (32 <= $5 >>> 0) {
+  if ($5 >>> 0 >= 32) {
    $3 = -1 >>> $3 | 0
   } else {
    $4 = -1 >>> $3 | 0;
@@ -35,7 +36,7 @@
   $5 = $3 & $0;
   $3 = $1 & $4;
   $4 = $6 & 31;
-  if (32 <= $6 >>> 0) {
+  if ($6 >>> 0 >= 32) {
    $3 = $5 << $4;
    $6 = 0;
   } else {
@@ -46,7 +47,7 @@
   $4 = 0 - $2 & 63;
   $3 = $4;
   $2 = $3 & 31;
-  if (32 <= $3 >>> 0) {
+  if ($3 >>> 0 >= 32) {
    $3 = -1 << $2;
    $2 = 0;
   } else {
@@ -56,7 +57,7 @@
   $0 = $2 & $0;
   $3 = $1 & $3;
   $1 = $4 & 31;
-  if (32 <= $4 >>> 0) {
+  if ($4 >>> 0 >= 32) {
    $2 = 0;
    $0 = $3 >>> $1 | 0;
   } else {
@@ -72,7 +73,7 @@
   var $3 = 0, $4 = 0, $5 = 0, $6 = 0, $7 = 0;
   $6 = $2 & 63;
   $3 = $6 & 31;
-  if (32 <= $6 >>> 0) {
+  if ($6 >>> 0 >= 32) {
    $4 = -1 << $3;
    $7 = 0;
   } else {
@@ -82,7 +83,7 @@
   $7 = $7 & $0;
   $3 = $1 & $4;
   $5 = $6 & 31;
-  if (32 <= $6 >>> 0) {
+  if ($6 >>> 0 >= 32) {
    $4 = 0;
    $6 = $3 >>> $5 | 0;
   } else {
@@ -92,7 +93,7 @@
   $7 = $4;
   $3 = 0 - $2 & 63;
   $5 = $3 & 31;
-  if (32 <= $3 >>> 0) {
+  if ($3 >>> 0 >= 32) {
    $4 = 0;
    $2 = -1 >>> $5 | 0;
   } else {
@@ -102,7 +103,7 @@
   $0 = $2 & $0;
   $1 = $1 & $4;
   $4 = $3 & 31;
-  if (32 <= $3 >>> 0) {
+  if ($3 >>> 0 >= 32) {
    $2 = $0 << $4;
    $0 = 0;
   } else {
@@ -120,20 +121,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var rotl = retasmFunc.rotl;
 export var rotr = retasmFunc.rotr;
diff --git a/binaryen/test/wasm2js/i64-select.2asm.js b/binaryen/test/wasm2js/i64-select.2asm.js
--- a/binaryen/test/wasm2js/i64-select.2asm.js
+++ b/binaryen/test/wasm2js/i64-select.2asm.js
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/i64-select.2asm.js.opt b/binaryen/test/wasm2js/i64-select.2asm.js.opt
--- a/binaryen/test/wasm2js/i64-select.2asm.js.opt
+++ b/binaryen/test/wasm2js/i64-select.2asm.js.opt
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/i64-shifts.2asm.js b/binaryen/test/wasm2js/i64-shifts.2asm.js
--- a/binaryen/test/wasm2js/i64-shifts.2asm.js
+++ b/binaryen/test/wasm2js/i64-shifts.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0, $0$hi, $1_1, $1$hi, $2_1, $2$hi) {
   $0 = $0 | 0;
   $0$hi = $0$hi | 0;
@@ -246,20 +247,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var shl_i64 = retasmFunc.shl_i64;
 export var shr_i64 = retasmFunc.shr_i64;
diff --git a/binaryen/test/wasm2js/i64-shifts.2asm.js.opt b/binaryen/test/wasm2js/i64-shifts.2asm.js.opt
--- a/binaryen/test/wasm2js/i64-shifts.2asm.js.opt
+++ b/binaryen/test/wasm2js/i64-shifts.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0, $1_1, $2_1, $3, $4) {
   $0 = $0 | 0;
   $1_1 = $1_1 | 0;
@@ -20,7 +21,7 @@
   $4 = $4 | 0;
   var $5 = 0;
   $5 = $2_1 & 31;
-  if (32 <= ($2_1 & 63) >>> 0) {
+  if (($2_1 & 63) >>> 0 >= 32) {
    $1_1 = $0 << $5;
    $0 = 0;
   } else {
@@ -38,7 +39,7 @@
   $4 = $4 | 0;
   var $5 = 0;
   $5 = $2_1 & 31;
-  if (32 <= ($2_1 & 63) >>> 0) {
+  if (($2_1 & 63) >>> 0 >= 32) {
    $2_1 = $1_1 >> 31;
    $0 = $1_1 >> $5;
   } else {
@@ -62,20 +63,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var shl_i64 = retasmFunc.shl_i64;
 export var shr_i64 = retasmFunc.shr_i64;
diff --git a/binaryen/test/wasm2js/if_unreachable.2asm.js b/binaryen/test/wasm2js/if_unreachable.2asm.js
--- a/binaryen/test/wasm2js/if_unreachable.2asm.js
+++ b/binaryen/test/wasm2js/if_unreachable.2asm.js
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/if_unreachable.2asm.js.opt b/binaryen/test/wasm2js/if_unreachable.2asm.js.opt
--- a/binaryen/test/wasm2js/if_unreachable.2asm.js.opt
+++ b/binaryen/test/wasm2js/if_unreachable.2asm.js.opt
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/indirect-select.2asm.js b/binaryen/test/wasm2js/indirect-select.2asm.js
--- a/binaryen/test/wasm2js/indirect-select.2asm.js
+++ b/binaryen/test/wasm2js/indirect-select.2asm.js
@@ -1,19 +1,20 @@
 import { table } from 'env';
 
-function asmFunc(global, env) {
+function asmFunc(env) {
  var FUNCTION_TABLE = env.table;
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(x) {
   x = x | 0;
   return FUNCTION_TABLE[(x ? 1 : 0) | 0]() | 0 | 0;
@@ -30,20 +31,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     table
   });
 export var foo_true = retasmFunc.foo_true;
diff --git a/binaryen/test/wasm2js/indirect-select.2asm.js.opt b/binaryen/test/wasm2js/indirect-select.2asm.js.opt
--- a/binaryen/test/wasm2js/indirect-select.2asm.js.opt
+++ b/binaryen/test/wasm2js/indirect-select.2asm.js.opt
@@ -1,19 +1,20 @@
 import { table } from 'env';
 
-function asmFunc(global, env) {
+function asmFunc(env) {
  var FUNCTION_TABLE = env.table;
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0($0_1) {
   $0_1 = $0_1 | 0;
   return FUNCTION_TABLE[!!$0_1 | 0]() | 0;
@@ -30,20 +31,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     table
   });
 export var foo_true = retasmFunc.foo_true;
diff --git a/binaryen/test/wasm2js/int_exprs.2asm.js b/binaryen/test/wasm2js/int_exprs.2asm.js
--- a/binaryen/test/wasm2js/int_exprs.2asm.js
+++ b/binaryen/test/wasm2js/int_exprs.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(x, y) {
   x = x | 0;
   y = y | 0;
@@ -229,20 +230,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var i32_no_fold_cmp_s_offset = retasmFunc.i32_no_fold_cmp_s_offset;
 export var i32_no_fold_cmp_u_offset = retasmFunc.i32_no_fold_cmp_u_offset;
@@ -250,19 +238,20 @@
 export var i64_no_fold_cmp_u_offset = retasmFunc.i64_no_fold_cmp_u_offset;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0(x, x$hi) {
@@ -326,38 +315,26 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i64_no_fold_wrap_extend_s = retasmFunc.i64_no_fold_wrap_extend_s;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0(x, x$hi) {
@@ -420,38 +397,26 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i64_no_fold_wrap_extend_u = retasmFunc.i64_no_fold_wrap_extend_u;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0(x) {
@@ -626,20 +591,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_no_fold_shl_shr_s = retasmFunc.i32_no_fold_shl_shr_s;
@@ -648,19 +600,20 @@
 export var i64_no_fold_shl_shr_u = retasmFunc.i64_no_fold_shl_shr_u;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0(x) {
@@ -835,20 +788,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_no_fold_shr_s_shl = retasmFunc.i32_no_fold_shr_s_shl;
@@ -857,19 +797,20 @@
 export var i64_no_fold_shr_u_shl = retasmFunc.i64_no_fold_shr_u_shl;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -1663,20 +1604,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_no_fold_div_s_mul = retasmFunc.i32_no_fold_div_s_mul;
@@ -1685,19 +1613,20 @@
 export var i64_no_fold_div_u_mul = retasmFunc.i64_no_fold_div_u_mul;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -2397,20 +2326,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_no_fold_div_s_self = retasmFunc.i32_no_fold_div_s_self;
@@ -2419,19 +2335,20 @@
 export var i64_no_fold_div_u_self = retasmFunc.i64_no_fold_div_u_self;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -3113,20 +3030,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_no_fold_rem_s_self = retasmFunc.i32_no_fold_rem_s_self;
@@ -3135,19 +3039,20 @@
 export var i64_no_fold_rem_u_self = retasmFunc.i64_no_fold_rem_u_self;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -3941,20 +3846,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_no_fold_mul_div_s = retasmFunc.i32_no_fold_mul_div_s;
@@ -3963,19 +3855,20 @@
 export var i64_no_fold_mul_div_u = retasmFunc.i64_no_fold_mul_div_u;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -4611,39 +4504,27 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_no_fold_div_s_2 = retasmFunc.i32_no_fold_div_s_2;
 export var i64_no_fold_div_s_2 = retasmFunc.i64_no_fold_div_s_2;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -5261,39 +5142,27 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_no_fold_rem_s_2 = retasmFunc.i32_no_fold_rem_s_2;
 export var i64_no_fold_rem_s_2 = retasmFunc.i64_no_fold_rem_s_2;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -5993,20 +5862,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_div_s_0 = retasmFunc.i32_div_s_0;
@@ -6015,19 +5871,20 @@
 export var i64_div_u_0 = retasmFunc.i64_div_u_0;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -6727,20 +6584,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_div_s_3 = retasmFunc.i32_div_s_3;
@@ -6749,19 +6593,20 @@
 export var i64_div_u_3 = retasmFunc.i64_div_u_3;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -7461,20 +7306,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_div_s_5 = retasmFunc.i32_div_s_5;
@@ -7483,19 +7315,20 @@
 export var i64_div_u_5 = retasmFunc.i64_div_u_5;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -8195,20 +8028,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_div_s_7 = retasmFunc.i32_div_s_7;
@@ -8217,19 +8037,20 @@
 export var i64_div_u_7 = retasmFunc.i64_div_u_7;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -8911,20 +8732,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_rem_s_3 = retasmFunc.i32_rem_s_3;
@@ -8933,19 +8741,20 @@
 export var i64_rem_u_3 = retasmFunc.i64_rem_u_3;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -9627,20 +9436,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_rem_s_5 = retasmFunc.i32_rem_s_5;
@@ -9649,19 +9445,20 @@
 export var i64_rem_u_5 = retasmFunc.i64_rem_u_5;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -10343,20 +10140,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_rem_s_7 = retasmFunc.i32_rem_s_7;
@@ -10365,19 +10149,20 @@
 export var i64_rem_u_7 = retasmFunc.i64_rem_u_7;
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
@@ -11013,20 +10798,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var i32_no_fold_div_neg1 = retasmFunc.i32_no_fold_div_neg1;
diff --git a/binaryen/test/wasm2js/labels.2asm.js b/binaryen/test/wasm2js/labels.2asm.js
--- a/binaryen/test/wasm2js/labels.2asm.js
+++ b/binaryen/test/wasm2js/labels.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   var $0_1 = 0;
   exit : {
@@ -341,20 +342,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var block = retasmFunc.block;
 export var loop1 = retasmFunc.loop1;
diff --git a/binaryen/test/wasm2js/left-to-right.2asm.js b/binaryen/test/wasm2js/left-to-right.2asm.js
--- a/binaryen/test/wasm2js/left-to-right.2asm.js
+++ b/binaryen/test/wasm2js/left-to-right.2asm.js
@@ -1,4 +1,5 @@
 
+  var bufferView;
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -25,27 +26,29 @@
     f32ScratchView[2] = value;
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
  var i64toi32_i32$HIGH_BITS = 0;
@@ -2037,6 +2040,7 @@
   return 32 | 0;
  }
  
+ bufferView = HEAPU8;
  var FUNCTION_TABLE = [i32_t0, i32_t1, i64_t0, i64_t1, f32_t0, f32_t1, f64_t0, f64_t1];
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
@@ -2048,18 +2052,18 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
+   bufferView = HEAPU8;
   }
   return oldPages;
  }
@@ -2163,25 +2167,8 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var i32_add = retasmFunc.i32_add;
 export var i32_sub = retasmFunc.i32_sub;
 export var i32_mul = retasmFunc.i32_mul;
diff --git a/binaryen/test/wasm2js/minified-memory.2asm.js b/binaryen/test/wasm2js/minified-memory.2asm.js
--- a/binaryen/test/wasm2js/minified-memory.2asm.js
+++ b/binaryen/test/wasm2js/minified-memory.2asm.js
@@ -1,28 +1,29 @@
 
-function asmFunc(global, env) {
+function asmFunc(env) {
  var memory = env.a;
  var buffer = memory.buffer;
  memory.grow = __wasm_memory_grow;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   return HEAP32[0 >> 2] | 0 | 0;
  }
@@ -37,19 +38,18 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
-   memory.buffer = newBuffer;
+   memory.buffer = buffer;
   }
   return oldPages;
  }
@@ -60,21 +60,7 @@
 }
 
 var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     a: { buffer : memasmFunc }
   });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/minified-memory.2asm.js.opt b/binaryen/test/wasm2js/minified-memory.2asm.js.opt
--- a/binaryen/test/wasm2js/minified-memory.2asm.js.opt
+++ b/binaryen/test/wasm2js/minified-memory.2asm.js.opt
@@ -1,28 +1,29 @@
 
-function asmFunc(global, env) {
+function asmFunc(env) {
  var memory = env.a;
  var buffer = memory.buffer;
  memory.grow = __wasm_memory_grow;
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   return HEAP32[0];
  }
@@ -37,19 +38,18 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
-   memory.buffer = newBuffer;
+   memory.buffer = buffer;
   }
   return oldPages;
  }
@@ -60,21 +60,7 @@
 }
 
 var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     a: { buffer : memasmFunc }
   });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/minus_minus.2asm.js b/binaryen/test/wasm2js/minus_minus.2asm.js
--- a/binaryen/test/wasm2js/minus_minus.2asm.js
+++ b/binaryen/test/wasm2js/minus_minus.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   return ~~- -7094.0 | 0;
  }
@@ -25,19 +26,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var func_44_invoker = retasmFunc.func_44_invoker;
diff --git a/binaryen/test/wasm2js/minus_minus.2asm.js.opt b/binaryen/test/wasm2js/minus_minus.2asm.js.opt
--- a/binaryen/test/wasm2js/minus_minus.2asm.js.opt
+++ b/binaryen/test/wasm2js/minus_minus.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1() {
   
  }
@@ -21,19 +22,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var func_44_invoker = retasmFunc.func_44_invoker;
diff --git a/binaryen/test/wasm2js/nested-selects.2asm.js b/binaryen/test/wasm2js/nested-selects.2asm.js
--- a/binaryen/test/wasm2js/nested-selects.2asm.js
+++ b/binaryen/test/wasm2js/nested-selects.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0) {
   $0 = $0 | 0;
   return (($0 | 0) < (0 | 0) ? -1 : ($0 | 0) > (0 | 0) ? 1 : 0) | 0;
@@ -22,19 +23,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var sign = retasmFunc.sign;
diff --git a/binaryen/test/wasm2js/nested-selects.2asm.js.opt b/binaryen/test/wasm2js/nested-selects.2asm.js.opt
--- a/binaryen/test/wasm2js/nested-selects.2asm.js.opt
+++ b/binaryen/test/wasm2js/nested-selects.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0) {
   $0 = $0 | 0;
   return (($0 | 0) < 0 ? -1 : ($0 | 0) > 0) | 0;
@@ -22,19 +23,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var sign = retasmFunc.sign;
diff --git a/binaryen/test/wasm2js/ordering.2asm.js b/binaryen/test/wasm2js/ordering.2asm.js
--- a/binaryen/test/wasm2js/ordering.2asm.js
+++ b/binaryen/test/wasm2js/ordering.2asm.js
@@ -1,19 +1,20 @@
 import { table } from 'env';
 
-function asmFunc(global, env) {
+function asmFunc(env) {
  var FUNCTION_TABLE = env.table;
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function main() {
   var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0, wasm2js_i32$2 = 0;
   FUNCTION_TABLE[foo(2 | 0) | 0 | 0](1) | 0;
@@ -53,20 +54,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     table
   });
 export var main = retasmFunc.main;
diff --git a/binaryen/test/wasm2js/ordering.2asm.js.opt b/binaryen/test/wasm2js/ordering.2asm.js.opt
--- a/binaryen/test/wasm2js/ordering.2asm.js.opt
+++ b/binaryen/test/wasm2js/ordering.2asm.js.opt
@@ -1,19 +1,20 @@
 import { table } from 'env';
 
-function asmFunc(global, env) {
+function asmFunc(env) {
  var FUNCTION_TABLE = env.table;
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function main() {
   FUNCTION_TABLE[1](1) | 0;
   FUNCTION_TABLE[4](1) | 0;
@@ -44,20 +45,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     table
   });
 export var main = retasmFunc.main;
diff --git a/binaryen/test/wasm2js/reinterpret.2asm.js b/binaryen/test/wasm2js/reinterpret.2asm.js
--- a/binaryen/test/wasm2js/reinterpret.2asm.js
+++ b/binaryen/test/wasm2js/reinterpret.2asm.js
@@ -29,19 +29,20 @@
     return f32ScratchView[2];
   }
       
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0) {
   $0 = $0 | 0;
   return ((wasm2js_scratch_store_f32((wasm2js_scratch_store_i32(2, $0), wasm2js_scratch_load_f32())), wasm2js_scratch_load_i32(2)) | 0) == ($0 | 0) | 0;
@@ -96,20 +97,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var i32_roundtrip = retasmFunc.i32_roundtrip;
 export var i64_roundtrip = retasmFunc.i64_roundtrip;
diff --git a/binaryen/test/wasm2js/reinterpret.2asm.js.opt b/binaryen/test/wasm2js/reinterpret.2asm.js.opt
--- a/binaryen/test/wasm2js/reinterpret.2asm.js.opt
+++ b/binaryen/test/wasm2js/reinterpret.2asm.js.opt
@@ -29,19 +29,20 @@
     return f32ScratchView[2];
   }
       
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $1($0) {
   $0 = $0 | 0;
   return ((wasm2js_scratch_store_f32((wasm2js_scratch_store_i32(2, $0), wasm2js_scratch_load_f32())), wasm2js_scratch_load_i32(2)) | 0) == ($0 | 0) | 0;
@@ -68,20 +69,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var i32_roundtrip = retasmFunc.i32_roundtrip;
 export var i64_roundtrip = retasmFunc.i64_roundtrip;
diff --git a/binaryen/test/wasm2js/reinterpret_scratch.2asm.js b/binaryen/test/wasm2js/reinterpret_scratch.2asm.js
--- a/binaryen/test/wasm2js/reinterpret_scratch.2asm.js
+++ b/binaryen/test/wasm2js/reinterpret_scratch.2asm.js
@@ -1,4 +1,5 @@
 
+  var bufferView;
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -17,27 +18,29 @@
     f32ScratchView[2] = value;
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   var i64toi32_i32$1 = 0, i64toi32_i32$0 = 0, $0_1 = Math_fround(0);
   wasm2js_scratch_store_f64(+(305419896.0));
@@ -48,6 +51,7 @@
   return HEAP32[0 >> 2] | 0 | 0;
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -57,23 +61,6 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/reinterpret_scratch.2asm.js.opt b/binaryen/test/wasm2js/reinterpret_scratch.2asm.js.opt
--- a/binaryen/test/wasm2js/reinterpret_scratch.2asm.js.opt
+++ b/binaryen/test/wasm2js/reinterpret_scratch.2asm.js.opt
@@ -1,4 +1,5 @@
 
+  var bufferView;
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -13,27 +14,29 @@
     f64ScratchView[0] = value;
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0() {
   var $0_1 = 0;
   wasm2js_scratch_store_f64(305419896.0);
@@ -43,6 +46,7 @@
   return HEAP32[0];
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -52,23 +56,6 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var foo = retasmFunc.foo;
diff --git a/binaryen/test/wasm2js/set_local.2asm.js b/binaryen/test/wasm2js/set_local.2asm.js
--- a/binaryen/test/wasm2js/set_local.2asm.js
+++ b/binaryen/test/wasm2js/set_local.2asm.js
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0() {
@@ -219,20 +220,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var type_local_i32 = retasmFunc.type_local_i32;
diff --git a/binaryen/test/wasm2js/sign_ext.2asm.js b/binaryen/test/wasm2js/sign_ext.2asm.js
--- a/binaryen/test/wasm2js/sign_ext.2asm.js
+++ b/binaryen/test/wasm2js/sign_ext.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(x) {
   x = x | 0;
   return x << 24 >> 24 | 0;
@@ -28,20 +29,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var test8 = retasmFunc.test8;
 export var test16 = retasmFunc.test16;
diff --git a/binaryen/test/wasm2js/sign_ext.2asm.js.opt b/binaryen/test/wasm2js/sign_ext.2asm.js.opt
--- a/binaryen/test/wasm2js/sign_ext.2asm.js.opt
+++ b/binaryen/test/wasm2js/sign_ext.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0($0_1) {
   $0_1 = $0_1 | 0;
   return $0_1 << 24 >> 24;
@@ -28,20 +29,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var test8 = retasmFunc.test8;
 export var test16 = retasmFunc.test16;
diff --git a/binaryen/test/wasm2js/stack-modified.2asm.js b/binaryen/test/wasm2js/stack-modified.2asm.js
--- a/binaryen/test/wasm2js/stack-modified.2asm.js
+++ b/binaryen/test/wasm2js/stack-modified.2asm.js
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0(var$0, var$0$hi) {
@@ -570,20 +571,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var fac_expr = retasmFunc.fac_expr;
diff --git a/binaryen/test/wasm2js/stack-modified.2asm.js.opt b/binaryen/test/wasm2js/stack-modified.2asm.js.opt
--- a/binaryen/test/wasm2js/stack-modified.2asm.js.opt
+++ b/binaryen/test/wasm2js/stack-modified.2asm.js.opt
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0($0_1, $1) {
@@ -67,20 +68,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var fac_expr = retasmFunc.fac_expr;
diff --git a/binaryen/test/wasm2js/start_func.2asm.js b/binaryen/test/wasm2js/start_func.2asm.js
--- a/binaryen/test/wasm2js/start_func.2asm.js
+++ b/binaryen/test/wasm2js/start_func.2asm.js
@@ -1,25 +1,27 @@
 
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function foo() {
   HEAP32[1 >> 2] = 2;
  }
@@ -35,17 +37,16 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
   }
   return oldPages;
@@ -56,22 +57,5 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
diff --git a/binaryen/test/wasm2js/start_func.2asm.js.opt b/binaryen/test/wasm2js/start_func.2asm.js.opt
--- a/binaryen/test/wasm2js/start_func.2asm.js.opt
+++ b/binaryen/test/wasm2js/start_func.2asm.js.opt
@@ -1,25 +1,27 @@
 
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function foo() {
   HEAP32[0] = 2;
  }
@@ -35,17 +37,16 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
   }
   return oldPages;
@@ -56,22 +57,5 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
diff --git a/binaryen/test/wasm2js/switch.2asm.js b/binaryen/test/wasm2js/switch.2asm.js
--- a/binaryen/test/wasm2js/switch.2asm.js
+++ b/binaryen/test/wasm2js/switch.2asm.js
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0(i) {
@@ -182,20 +183,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var stmt = retasmFunc.stmt;
diff --git a/binaryen/test/wasm2js/tee_local.2asm.js b/binaryen/test/wasm2js/tee_local.2asm.js
--- a/binaryen/test/wasm2js/tee_local.2asm.js
+++ b/binaryen/test/wasm2js/tee_local.2asm.js
@@ -1,18 +1,19 @@
 import { setTempRet0 } from 'env';
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0() {
@@ -326,20 +327,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
   });
 export var type_local_i32 = retasmFunc.type_local_i32;
diff --git a/binaryen/test/wasm2js/traps.2asm.js b/binaryen/test/wasm2js/traps.2asm.js
--- a/binaryen/test/wasm2js/traps.2asm.js
+++ b/binaryen/test/wasm2js/traps.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
  var i64toi32_i32$HIGH_BITS = 0;
@@ -728,39 +729,27 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var no_dce_i32_div_s = retasmFunc.no_dce_i32_div_s;
 export var no_dce_i32_div_u = retasmFunc.no_dce_i32_div_u;
 export var no_dce_i64_div_s = retasmFunc.no_dce_i64_div_s;
 export var no_dce_i64_div_u = retasmFunc.no_dce_i64_div_u;
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var __wasm_intrinsics_temp_i64 = 0;
  var __wasm_intrinsics_temp_i64$hi = 0;
  var i64toi32_i32$HIGH_BITS = 0;
@@ -1459,39 +1448,27 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var no_dce_i32_rem_s = retasmFunc.no_dce_i32_rem_s;
 export var no_dce_i32_rem_u = retasmFunc.no_dce_i32_rem_u;
 export var no_dce_i64_rem_s = retasmFunc.no_dce_i64_rem_s;
 export var no_dce_i64_rem_u = retasmFunc.no_dce_i64_rem_u;
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(x) {
   x = Math_fround(x);
   ~~x;
@@ -1592,20 +1569,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var no_dce_i32_trunc_f32_s = retasmFunc.no_dce_i32_trunc_f32_s;
 export var no_dce_i32_trunc_f32_u = retasmFunc.no_dce_i32_trunc_f32_u;
@@ -1616,27 +1580,29 @@
 export var no_dce_i64_trunc_f64_s = retasmFunc.no_dce_i64_trunc_f64_s;
 export var no_dce_i64_trunc_f64_u = retasmFunc.no_dce_i64_trunc_f64_u;
 
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  function $0(i) {
   i = i | 0;
   HEAP32[i >> 2] | 0;
@@ -1723,17 +1689,16 @@
   var newPages = oldPages + pagesToAdd | 0;
   if ((oldPages < newPages) && (newPages < 65536)) {
    var newBuffer = new ArrayBuffer(Math_imul(newPages, 65536));
-   var newHEAP8 = new global.Int8Array(newBuffer);
+   var newHEAP8 = new Int8Array(newBuffer);
    newHEAP8.set(HEAP8);
-   HEAP8 = newHEAP8;
-   HEAP8 = new global.Int8Array(newBuffer);
-   HEAP16 = new global.Int16Array(newBuffer);
-   HEAP32 = new global.Int32Array(newBuffer);
-   HEAPU8 = new global.Uint8Array(newBuffer);
-   HEAPU16 = new global.Uint16Array(newBuffer);
-   HEAPU32 = new global.Uint32Array(newBuffer);
-   HEAPF32 = new global.Float32Array(newBuffer);
-   HEAPF64 = new global.Float64Array(newBuffer);
+   HEAP8 = new Int8Array(newBuffer);
+   HEAP16 = new Int16Array(newBuffer);
+   HEAP32 = new Int32Array(newBuffer);
+   HEAPU8 = new Uint8Array(newBuffer);
+   HEAPU16 = new Uint16Array(newBuffer);
+   HEAPU32 = new Uint32Array(newBuffer);
+   HEAPF32 = new Float32Array(newBuffer);
+   HEAPF64 = new Float64Array(newBuffer);
    buffer = newBuffer;
   }
   return oldPages;
@@ -1757,25 +1722,8 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
-  },
-  memasmFunc
-);
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
+  });
 export var no_dce_i32_load = retasmFunc.no_dce_i32_load;
 export var no_dce_i32_load16_s = retasmFunc.no_dce_i32_load16_s;
 export var no_dce_i32_load16_u = retasmFunc.no_dce_i32_load16_u;
diff --git a/binaryen/test/wasm2js/unaligned.2asm.js b/binaryen/test/wasm2js/unaligned.2asm.js
--- a/binaryen/test/wasm2js/unaligned.2asm.js
+++ b/binaryen/test/wasm2js/unaligned.2asm.js
@@ -1,5 +1,6 @@
 import { setTempRet0 } from 'env';
 
+  var bufferView;
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -30,27 +31,29 @@
     f32ScratchView[2] = value;
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0() {
@@ -157,6 +160,7 @@
   return $0_1 | 0;
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -173,26 +177,9 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
-  },
-  memasmFunc
-);
+  });
 export var i32_load = retasmFunc.i32_load;
 export var i64_load = retasmFunc.i64_load;
 export var f32_load = retasmFunc.f32_load;
diff --git a/binaryen/test/wasm2js/unaligned.2asm.js.opt b/binaryen/test/wasm2js/unaligned.2asm.js.opt
--- a/binaryen/test/wasm2js/unaligned.2asm.js.opt
+++ b/binaryen/test/wasm2js/unaligned.2asm.js.opt
@@ -1,5 +1,6 @@
 import { setTempRet0 } from 'env';
 
+  var bufferView;
 
   var scratchBuffer = new ArrayBuffer(16);
   var i32ScratchView = new Int32Array(scratchBuffer);
@@ -26,27 +27,29 @@
     return f32ScratchView[2];
   }
       
-function asmFunc(global, env, buffer) {
- var HEAP8 = new global.Int8Array(buffer);
- var HEAP16 = new global.Int16Array(buffer);
- var HEAP32 = new global.Int32Array(buffer);
- var HEAPU8 = new global.Uint8Array(buffer);
- var HEAPU16 = new global.Uint16Array(buffer);
- var HEAPU32 = new global.Uint32Array(buffer);
- var HEAPF32 = new global.Float32Array(buffer);
- var HEAPF64 = new global.Float64Array(buffer);
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var buffer = new ArrayBuffer(65536);
+ var HEAP8 = new Int8Array(buffer);
+ var HEAP16 = new Int16Array(buffer);
+ var HEAP32 = new Int32Array(buffer);
+ var HEAPU8 = new Uint8Array(buffer);
+ var HEAPU16 = new Uint16Array(buffer);
+ var HEAPU32 = new Uint32Array(buffer);
+ var HEAPF32 = new Float32Array(buffer);
+ var HEAPF64 = new Float64Array(buffer);
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var setTempRet0 = env.setTempRet0;
  var i64toi32_i32$HIGH_BITS = 0;
  function $0() {
@@ -110,6 +113,7 @@
   return $0_1;
  }
  
+ bufferView = HEAPU8;
  function __wasm_memory_size() {
   return buffer.byteLength / 65536 | 0;
  }
@@ -126,26 +130,9 @@
  };
 }
 
-var memasmFunc = new ArrayBuffer(65536);
-var bufferView = new Uint8Array(memasmFunc);
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); },
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); },
     setTempRet0
-  },
-  memasmFunc
-);
+  });
 export var i32_load = retasmFunc.i32_load;
 export var i64_load = retasmFunc.i64_load;
 export var f32_load = retasmFunc.f32_load;
diff --git a/binaryen/test/wasm2js/unary-ops.2asm.js b/binaryen/test/wasm2js/unary-ops.2asm.js
--- a/binaryen/test/wasm2js/unary-ops.2asm.js
+++ b/binaryen/test/wasm2js/unary-ops.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var i64toi32_i32$HIGH_BITS = 0;
  function $1($0) {
   $0 = $0 | 0;
@@ -516,20 +517,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var i32_popcnt = retasmFunc.i32_popcnt;
 export var check_popcnt_i64 = retasmFunc.check_popcnt_i64;
diff --git a/binaryen/test/wasm2js/unary-ops.2asm.js.opt b/binaryen/test/wasm2js/unary-ops.2asm.js.opt
--- a/binaryen/test/wasm2js/unary-ops.2asm.js.opt
+++ b/binaryen/test/wasm2js/unary-ops.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var i64toi32_i32$HIGH_BITS = 0;
  function $1($0) {
   $0 = $0 | 0;
@@ -26,7 +27,7 @@
  function $7($0) {
   $0 = $0 | 0;
   if ($0) {
-   $0 = 31 - Math_clz32($0 + -1 ^ $0) | 0
+   $0 = 31 - Math_clz32($0 - 1 ^ $0) | 0
   } else {
    $0 = 32
   }
@@ -71,16 +72,14 @@
  function __wasm_ctz_i64($0, $1_1) {
   var $2 = 0, $3 = 0;
   if ($0 | $1_1) {
-   $3 = $1_1 + -1 | 0;
-   $2 = $0 + -1 | 0;
-   if (($2 | 0) != -1) {
-    $3 = $3 + 1 | 0
-   }
-   $2 = Math_clz32($0 ^ $2) + 32 | 0;
-   $0 = Math_clz32($1_1 ^ $3);
-   $0 = ($0 | 0) == 32 ? $2 : $0;
+   $2 = $1_1 - 1 | 0;
+   $3 = $0 - 1 | 0;
+   $2 = ($3 | 0) != -1 ? $2 + 1 | 0 : $2;
+   $3 = Math_clz32($0 ^ $3) + 32 | 0;
+   $0 = Math_clz32($1_1 ^ $2);
+   $0 = ($0 | 0) == 32 ? $3 : $0;
    $1_1 = 63 - $0 | 0;
-   i64toi32_i32$HIGH_BITS = 0 - (63 < $0 >>> 0) | 0;
+   i64toi32_i32$HIGH_BITS = 0 - ($0 >>> 0 > 63) | 0;
    return $1_1;
   }
   i64toi32_i32$HIGH_BITS = 0;
@@ -104,17 +103,15 @@
  function __wasm_popcnt_i64($0, $1_1) {
   var $2 = 0, $3 = 0, $4 = 0, $5 = 0;
   while (1) {
-   $5 = $3;
-   $2 = $4;
+   $5 = $4;
+   $2 = $3;
    if ($0 | $1_1) {
     $2 = $0;
     $0 = $2 - 1 & $2;
     $1_1 = $1_1 - ($2 >>> 0 < 1) & $1_1;
-    $2 = $3 + 1 | 0;
-    if ($2 >>> 0 < 1) {
-     $4 = $4 + 1 | 0
-    }
-    $3 = $2;
+    $2 = $4 + 1 | 0;
+    $3 = $2 >>> 0 < 1 ? $3 + 1 | 0 : $3;
+    $4 = $2;
     continue;
    }
    break;
@@ -136,20 +133,7 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var i32_popcnt = retasmFunc.i32_popcnt;
 export var check_popcnt_i64 = retasmFunc.check_popcnt_i64;
diff --git a/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js b/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js
--- a/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js
+++ b/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js.opt b/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js.opt
--- a/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js.opt
+++ b/binaryen/test/wasm2js/unreachable-get-cycle.2asm.js.opt
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/unreachable-insts.2asm.js b/binaryen/test/wasm2js/unreachable-insts.2asm.js
--- a/binaryen/test/wasm2js/unreachable-insts.2asm.js
+++ b/binaryen/test/wasm2js/unreachable-insts.2asm.js
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/unreachable-insts.2asm.js.opt b/binaryen/test/wasm2js/unreachable-insts.2asm.js.opt
--- a/binaryen/test/wasm2js/unreachable-insts.2asm.js.opt
+++ b/binaryen/test/wasm2js/unreachable-insts.2asm.js.opt
@@ -1,34 +1,22 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  return {
   
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
diff --git a/binaryen/test/wasm2js/unreachable-later.2asm.js b/binaryen/test/wasm2js/unreachable-later.2asm.js
--- a/binaryen/test/wasm2js/unreachable-later.2asm.js
+++ b/binaryen/test/wasm2js/unreachable-later.2asm.js
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var global$0 = 10;
  function $0($0_1) {
   $0_1 = $0_1 | 0;
@@ -63,19 +64,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var func_50 = retasmFunc.func_50;
diff --git a/binaryen/test/wasm2js/unreachable-later.2asm.js.opt b/binaryen/test/wasm2js/unreachable-later.2asm.js.opt
--- a/binaryen/test/wasm2js/unreachable-later.2asm.js.opt
+++ b/binaryen/test/wasm2js/unreachable-later.2asm.js.opt
@@ -1,17 +1,18 @@
 
-function asmFunc(global, env) {
- var Math_imul = global.Math.imul;
- var Math_fround = global.Math.fround;
- var Math_abs = global.Math.abs;
- var Math_clz32 = global.Math.clz32;
- var Math_min = global.Math.min;
- var Math_max = global.Math.max;
- var Math_floor = global.Math.floor;
- var Math_ceil = global.Math.ceil;
- var Math_sqrt = global.Math.sqrt;
+function asmFunc(env) {
+ var Math_imul = Math.imul;
+ var Math_fround = Math.fround;
+ var Math_abs = Math.abs;
+ var Math_clz32 = Math.clz32;
+ var Math_min = Math.min;
+ var Math_max = Math.max;
+ var Math_floor = Math.floor;
+ var Math_ceil = Math.ceil;
+ var Math_trunc = Math.trunc;
+ var Math_sqrt = Math.sqrt;
  var abort = env.abort;
- var nan = global.NaN;
- var infinity = global.Infinity;
+ var nan = NaN;
+ var infinity = Infinity;
  var global$0 = 10;
  function $0($0_1) {
   $0_1 = $0_1 | 0;
@@ -36,19 +37,6 @@
  };
 }
 
-var retasmFunc = asmFunc({
-    Math,
-    Int8Array,
-    Uint8Array,
-    Int16Array,
-    Uint16Array,
-    Int32Array,
-    Uint32Array,
-    Float32Array,
-    Float64Array,
-    NaN,
-    Infinity
-  }, {
-    abort: function() { throw new Error('abort'); }
+var retasmFunc = asmFunc(  { abort: function() { throw new Error('abort'); }
   });
 export var func_50 = retasmFunc.func_50;
diff --git a/binaryen/third_party/llvm-project/DWARFEmitter.cpp b/binaryen/third_party/llvm-project/DWARFEmitter.cpp
--- a/binaryen/third_party/llvm-project/DWARFEmitter.cpp
+++ b/binaryen/third_party/llvm-project/DWARFEmitter.cpp
@@ -190,9 +190,11 @@
   // XXX BINARYEN Make sure we emit the right size. We should not change the
   // size as we only modify relocatable fields like addresses, and such fields
   // have a fixed size, so any change is a bug.
+  // We make an exception for AddrSizeChanged, which happens when we have run
+  // the Memory64Lowering pass to turn wasm64 into wasm32.
   void onEndCompileUnit(const DWARFYAML::Unit &CU) {
     size_t EndPos = OS.tell();
-    if (EndPos - StartPos != CU.Length.getLength()) {
+    if (EndPos - StartPos != CU.Length.getLength() && !CU.AddrSizeChanged) {
       llvm_unreachable("compile unit size was incorrect");
     }
   }
diff --git a/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFYAML.h b/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFYAML.h
--- a/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFYAML.h
+++ b/binaryen/third_party/llvm-project/include/llvm/ObjectYAML/DWARFYAML.h
@@ -128,6 +128,7 @@
   llvm::dwarf::UnitType Type; // Added in DWARF 5
   uint32_t AbbrOffset;
   uint8_t AddrSize;
+  bool AddrSizeChanged = false;  // XXX BINARYEN
   std::vector<Entry> Entries;
 };
 
diff --git a/src/Binaryen/Expression.hs b/src/Binaryen/Expression.hs
--- a/src/Binaryen/Expression.hs
+++ b/src/Binaryen/Expression.hs
@@ -406,7 +406,7 @@
 
 foreign import ccall unsafe "BinaryenRefFunc"
   refFunc ::
-    Module -> Ptr CChar -> IO Expression
+    Module -> Ptr CChar -> Type -> IO Expression
 
 foreign import ccall unsafe "BinaryenTry"
   try ::
diff --git a/src/Binaryen/Index.hs b/src/Binaryen/Index.hs
--- a/src/Binaryen/Index.hs
+++ b/src/Binaryen/Index.hs
@@ -1,17 +1,25 @@
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
 -- | The Binaryen index type.
 --
 -- See <https://github.com/WebAssembly/binaryen/blob/master/src/binaryen-c.h>
 -- for API documentation.
 --
 -- This module is intended to be imported qualified.
-
-{-# LANGUAGE DerivingStrategies #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-
 module Binaryen.Index where
 
 import Data.Word (Word32)
 import Foreign (Storable)
 
 newtype Index = Index Word32
-  deriving newtype (Eq, Num, Show, Storable)
+  deriving newtype
+    ( Enum,
+      Eq,
+      Integral,
+      Num,
+      Ord,
+      Real,
+      Show,
+      Storable
+    )
diff --git a/src/Binaryen/Module.hs b/src/Binaryen/Module.hs
--- a/src/Binaryen/Module.hs
+++ b/src/Binaryen/Module.hs
@@ -1,26 +1,36 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
 -- | Modules.
 --
 -- See <https://github.com/WebAssembly/binaryen/blob/master/src/binaryen-c.h>
 -- for API documentation.
 --
 -- This module is intended to be imported qualified.
-
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-
 module Binaryen.Module where
 
-import Binaryen.Index
 import Binaryen.Event
 import Binaryen.Export
 import Binaryen.Expression
 import Binaryen.Features
 import Binaryen.Function
 import Binaryen.Global
+import Binaryen.Index
 import Binaryen.Type
 import Data.Int (Int8)
-import Data.Word (Word8, Word32)
-import Foreign (Ptr, Storable)
-import Foreign.C (CChar(..), CInt(..), CSize(..), CUIntPtr(..))
+import Data.Word
+  ( Word32,
+    Word8,
+  )
+import Foreign
+  ( Ptr,
+    Storable,
+  )
+import Foreign.C
+  ( CChar (..),
+    CInt (..),
+    CSize (..),
+    CUIntPtr (..),
+  )
 
 newtype Module = Module (Ptr Module)
   deriving (Eq, Show, Storable)
@@ -54,7 +64,7 @@
 
 foreign import ccall unsafe "BinaryenGetNumFunctions"
   getNumFunctions ::
-    Module -> IO Word32
+    Module -> IO Index
 
 foreign import ccall unsafe "BinaryenGetFunctionByIndex"
   getFunctionByIndex ::
@@ -258,7 +268,7 @@
 
 foreign import ccall unsafe "BinaryenGetNumExports"
   getNumExports ::
-    Module -> IO Word32
+    Module -> IO Index
 
 foreign import ccall unsafe "BinaryenGetExportByIndex"
   getExportByIndex ::
diff --git a/src/Binaryen/Op.hs b/src/Binaryen/Op.hs
--- a/src/Binaryen/Op.hs
+++ b/src/Binaryen/Op.hs
@@ -536,10 +536,6 @@
 
 foreign import ccall unsafe "BinaryenNegVecI64x2" negVecI64x2 :: Op
 
-foreign import ccall unsafe "BinaryenAnyTrueVecI64x2" anyTrueVecI64x2 :: Op
-
-foreign import ccall unsafe "BinaryenAllTrueVecI64x2" allTrueVecI64x2 :: Op
-
 foreign import ccall unsafe "BinaryenShlVecI64x2" shlVecI64x2 :: Op
 
 foreign import ccall unsafe "BinaryenShrSVecI64x2" shrSVecI64x2 :: Op
